Merge pull request 'backend: Fix various lints in services/note' (#206) from backend-services-note into main
All checks were successful
ci/woodpecker/push/lint-foundkey-js Pipeline was successful
ci/woodpecker/push/lint-backend Pipeline was successful
ci/woodpecker/push/build Pipeline was successful
ci/woodpecker/push/lint-client Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
All checks were successful
ci/woodpecker/push/lint-foundkey-js Pipeline was successful
ci/woodpecker/push/lint-backend Pipeline was successful
ci/woodpecker/push/build Pipeline was successful
ci/woodpecker/push/lint-client Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
Reviewed-on: #206
This commit is contained in:
commit
c36cca30cb
21 changed files with 113 additions and 117 deletions
|
@ -24,7 +24,7 @@ export type Source = {
|
|||
db?: number;
|
||||
prefix?: string;
|
||||
};
|
||||
elasticsearch: {
|
||||
elasticsearch?: {
|
||||
host: string;
|
||||
port: number;
|
||||
ssl?: boolean;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import create from '@/services/note/reaction/create.js';
|
||||
import { createReaction } from '@/services/note/reaction/create.js';
|
||||
import { ILike, getApId } from '../type.js';
|
||||
import { fetchNote, extractEmojis } from '../models/note.js';
|
||||
|
||||
|
@ -11,7 +11,7 @@ export default async (actor: CacheableRemoteUser, activity: ILike) => {
|
|||
|
||||
await extractEmojis(activity.tag || [], actor.host).catch(() => null);
|
||||
|
||||
return await create(actor, note, activity._misskey_reaction || activity.content || activity.name).catch(e => {
|
||||
return await createReaction(actor, note, activity._misskey_reaction || activity.content || activity.name).catch(e => {
|
||||
if (e.id === '51c42bb4-931a-456b-bff7-e5a8a70dd298') {
|
||||
return 'skip: already reacted';
|
||||
} else {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import deleteReaction from '@/services/note/reaction/delete.js';
|
||||
import { deleteReaction } from '@/services/note/reaction/delete.js';
|
||||
import { ILike, getApId } from '@/remote/activitypub/type.js';
|
||||
import { fetchNote } from '@/remote/activitypub/models/note.js';
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import config from '@/config/index.js';
|
|||
import post from '@/services/note/create.js';
|
||||
import { CacheableRemoteUser } from '@/models/entities/user.js';
|
||||
import { unique, toArray, toSingle } from '@/prelude/array.js';
|
||||
import vote from '@/services/note/polls/vote.js';
|
||||
import { vote } from '@/services/note/polls/vote.js';
|
||||
import { DriveFile } from '@/models/entities/drive-file.js';
|
||||
import { deliverQuestionUpdate } from '@/services/note/polls/update.js';
|
||||
import { extractDbHost, toPuny } from '@/misc/convert-host.js';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import readNote from '@/services/note/read.js';
|
||||
import { readNote } from '@/services/note/read.js';
|
||||
import { Antennas, Notes, AntennaNotes } from '@/models/index.js';
|
||||
import { makePaginationQuery } from '../../common/make-pagination-query.js';
|
||||
import { generateVisibilityQuery } from '../../common/generate-visibility-query.js';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Brackets } from 'typeorm';
|
||||
import { notificationTypes } from 'foundkey-js';
|
||||
import { Notifications, Followings, Mutings, Users, UserProfiles } from '@/models/index.js';
|
||||
import read from '@/services/note/read.js';
|
||||
import { readNote } from '@/services/note/read.js';
|
||||
import { readNotification } from '../../common/read-notification.js';
|
||||
import define from '../../define.js';
|
||||
import { makePaginationQuery } from '../../common/make-pagination-query.js';
|
||||
|
@ -137,7 +137,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
const notes = notifications.filter(notification => ['mention', 'reply', 'quote'].includes(notification.type)).map(notification => notification.note!);
|
||||
|
||||
if (notes.length > 0) {
|
||||
read(user.id, notes);
|
||||
readNote(user.id, notes);
|
||||
}
|
||||
|
||||
return await Notifications.packMany(notifications, user.id);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Brackets } from 'typeorm';
|
||||
import { noteVisibilities } from 'foundkey-js';
|
||||
import read from '@/services/note/read.js';
|
||||
import { readNote } from '@/services/note/read.js';
|
||||
import { Notes, Followings } from '@/models/index.js';
|
||||
import define from '../../define.js';
|
||||
import { generateVisibilityQuery } from '../../common/generate-visibility-query.js';
|
||||
|
@ -79,7 +79,7 @@ export default define(meta, paramDef, async (ps, user) => {
|
|||
|
||||
const mentions = await query.take(ps.limit).getMany();
|
||||
|
||||
read(user.id, mentions);
|
||||
readNote(user.id, mentions);
|
||||
|
||||
return await Notes.packMany(mentions, user);
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import createReaction from '@/services/note/reaction/create.js';
|
||||
import { createReaction } from '@/services/note/reaction/create.js';
|
||||
import define from '../../../define.js';
|
||||
import { getNote } from '../../../common/getters.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import deleteReaction from '@/services/note/reaction/delete.js';
|
||||
import { deleteReaction } from '@/services/note/reaction/delete.js';
|
||||
import { SECOND, HOUR } from '@/const.js';
|
||||
import define from '../../../define.js';
|
||||
import { getNote } from '../../../common/getters.js';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { noteNotificationTypes } from 'foundkey-js';
|
||||
import { Notes, NoteThreadMutings, NoteWatchings } from '@/models/index.js';
|
||||
import { genId } from '@/misc/gen-id.js';
|
||||
import readNote from '@/services/note/read.js';
|
||||
import { readNote } from '@/services/note/read.js';
|
||||
import define from '../../../define.js';
|
||||
import { getNote } from '../../../common/getters.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import watch from '@/services/note/watch.js';
|
||||
import { watch } from '@/services/note/watch.js';
|
||||
import define from '../../../define.js';
|
||||
import { getNote } from '../../../common/getters.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import unwatch from '@/services/note/unwatch.js';
|
||||
import { unwatch } from '@/services/note/unwatch.js';
|
||||
import define from '../../../define.js';
|
||||
import { getNote } from '../../../common/getters.js';
|
||||
import { ApiError } from '../../../error.js';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { EventEmitter } from 'events';
|
||||
import * as websocket from 'websocket';
|
||||
import readNote from '@/services/note/read.js';
|
||||
import { readNote } from '@/services/note/read.js';
|
||||
import { User } from '@/models/entities/user.js';
|
||||
import { Channel as ChannelModel } from '@/models/entities/channel.js';
|
||||
import { Followings, Mutings, RenoteMutings, UserProfiles, ChannelFollowings, Blockings } from '@/models/index.js';
|
||||
|
|
|
@ -35,6 +35,7 @@ import { webhookDeliver } from '@/queue/index.js';
|
|||
import { Cache } from '@/misc/cache.js';
|
||||
import { UserProfile } from '@/models/entities/user-profile.js';
|
||||
import { getActiveWebhooks } from '@/misc/webhook-cache.js';
|
||||
import { IActivity } from '@/remote/activitypub/type.js';
|
||||
import { updateHashtags } from '../update-hashtag.js';
|
||||
import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc.js';
|
||||
import { createNotification } from '../create-notification.js';
|
||||
|
@ -59,14 +60,14 @@ class NotificationManager {
|
|||
this.queue = [];
|
||||
}
|
||||
|
||||
public push(notifiee: ILocalUser['id'], reason: NotificationType) {
|
||||
// 自分自身へは通知しない
|
||||
public push(notifiee: ILocalUser['id'], reason: NotificationType): void {
|
||||
// No notification to yourself.
|
||||
if (this.notifier.id === notifiee) return;
|
||||
|
||||
const exist = this.queue.find(x => x.target === notifiee);
|
||||
|
||||
if (exist) {
|
||||
// 「メンションされているかつ返信されている」場合は、メンションとしての通知ではなく返信としての通知にする
|
||||
// If you have been "mentioned and replied to," make the notification as a reply, not as a mention.
|
||||
if (reason !== 'mention') {
|
||||
exist.reason = reason;
|
||||
}
|
||||
|
@ -78,7 +79,7 @@ class NotificationManager {
|
|||
}
|
||||
}
|
||||
|
||||
public async deliver() {
|
||||
public async deliver(): Promise<void> {
|
||||
for (const x of this.queue) {
|
||||
// check if the sender or thread are muted
|
||||
const userMuted = await Mutings.findOneBy({
|
||||
|
@ -119,7 +120,7 @@ type Option = {
|
|||
poll?: IPoll | null;
|
||||
localOnly?: boolean | null;
|
||||
cw?: string | null;
|
||||
visibility?: string;
|
||||
visibility?: 'home' | 'public' | 'followers' | 'specified';
|
||||
visibleUsers?: MinimumUser[] | null;
|
||||
channel?: Channel | null;
|
||||
apMentions?: MinimumUser[] | null;
|
||||
|
@ -130,9 +131,9 @@ type Option = {
|
|||
app?: App | null;
|
||||
};
|
||||
|
||||
export default async (user: { id: User['id']; username: User['username']; host: User['host']; isSilenced: User['isSilenced']; createdAt: User['createdAt']; }, 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']; createdAt: User['createdAt']; }, data: Option, silent = false): Promise<Note> => new Promise<Note>(async (res, rej) => {
|
||||
// If you reply outside the channel, adjust to the scope of the target
|
||||
// (I think this could be done client-side, but server-side for now)
|
||||
if (data.reply && data.channel && data.reply.channelId !== data.channel.id) {
|
||||
if (data.reply.channelId) {
|
||||
data.channel = await Channels.findOneBy({ id: data.reply.channelId });
|
||||
|
@ -141,9 +142,9 @@ export default async (user: { id: User['id']; username: User['username']; host:
|
|||
}
|
||||
}
|
||||
|
||||
// チャンネル内にリプライしたら対象のスコープに合わせる
|
||||
// (クライアントサイドでやっても良い処理だと思うけどとりあえずサーバーサイドで)
|
||||
if (data.reply && (data.channel == null) && data.reply.channelId) {
|
||||
// When you reply to a channel, adjust the scope to that of the target.
|
||||
// (I think this could be done client-side, but server-side for now)
|
||||
if (data.reply?.channelId && (data.channel == null)) {
|
||||
data.channel = await Channels.findOneBy({ id: data.reply.channelId });
|
||||
}
|
||||
|
||||
|
@ -154,32 +155,32 @@ export default async (user: { id: User['id']; username: User['username']; host:
|
|||
if (data.channel != null) data.visibleUsers = [];
|
||||
if (data.channel != null) data.localOnly = true;
|
||||
|
||||
// サイレンス
|
||||
// silence
|
||||
if (user.isSilenced && data.visibility === 'public' && data.channel == null) {
|
||||
data.visibility = 'home';
|
||||
}
|
||||
|
||||
// Renote対象が「ホームまたは全体」以外の公開範囲ならreject
|
||||
// Reject if the target of the renote is not Home or Public.
|
||||
if (data.renote && data.renote.visibility !== 'public' && data.renote.visibility !== 'home' && data.renote.userId !== user.id) {
|
||||
return rej('Renote target is not public or home');
|
||||
}
|
||||
|
||||
// Renote対象がpublicではないならhomeにする
|
||||
// If the target of the renote is not public, make it home.
|
||||
if (data.renote && data.renote.visibility !== 'public' && data.visibility === 'public') {
|
||||
data.visibility = 'home';
|
||||
}
|
||||
|
||||
// Renote対象がfollowersならfollowersにする
|
||||
// If the target of Renote is followers, make it followers.
|
||||
if (data.renote && data.renote.visibility === 'followers') {
|
||||
data.visibility = 'followers';
|
||||
}
|
||||
|
||||
// ローカルのみをRenoteしたらローカルのみにする
|
||||
// Ff the original note is local-only, make the renote also local-only.
|
||||
if (data.renote && data.renote.localOnly && data.channel == null) {
|
||||
data.localOnly = true;
|
||||
}
|
||||
|
||||
// ローカルのみにリプライしたらローカルのみにする
|
||||
// If you reply to local only, make it local only.
|
||||
if (data.reply && data.reply.localOnly && data.channel == null) {
|
||||
data.localOnly = true;
|
||||
}
|
||||
|
@ -196,10 +197,10 @@ export default async (user: { id: User['id']; username: User['username']; host:
|
|||
|
||||
// Parse MFM if needed
|
||||
if (!tags || !emojis || !mentionedUsers) {
|
||||
const tokens = data.text ? mfm.parse(data.text)! : [];
|
||||
const cwTokens = data.cw ? mfm.parse(data.cw)! : [];
|
||||
const choiceTokens = data.poll && data.poll.choices
|
||||
? concat(data.poll.choices.map(choice => mfm.parse(choice)!))
|
||||
const tokens = data.text ? mfm.parse(data.text) : [];
|
||||
const cwTokens = data.cw ? mfm.parse(data.cw) : [];
|
||||
const choiceTokens = data.poll?.choices
|
||||
? concat(data.poll.choices.map(choice => mfm.parse(choice)))
|
||||
: [];
|
||||
|
||||
const combinedTokens = tokens.concat(cwTokens).concat(choiceTokens);
|
||||
|
@ -213,8 +214,8 @@ export default async (user: { id: User['id']; username: User['username']; host:
|
|||
|
||||
tags = tags.filter(tag => Array.from(tag || '').length <= 128).splice(0, 32);
|
||||
|
||||
if (data.reply && (user.id !== data.reply.userId) && !mentionedUsers.some(u => u.id === data.reply!.userId)) {
|
||||
mentionedUsers.push(await Users.findOneByOrFail({ id: data.reply!.userId }));
|
||||
if (data.reply && (user.id !== data.reply.userId) && !mentionedUsers.some(u => u.id === data.reply?.userId)) {
|
||||
mentionedUsers.push(await Users.findOneByOrFail({ id: data.reply.userId }));
|
||||
}
|
||||
|
||||
if (data.visibility === 'specified') {
|
||||
|
@ -226,8 +227,8 @@ export default async (user: { id: User['id']; username: User['username']; host:
|
|||
}
|
||||
}
|
||||
|
||||
if (data.reply && !data.visibleUsers.some(x => x.id === data.reply!.userId)) {
|
||||
data.visibleUsers.push(await Users.findOneByOrFail({ id: data.reply!.userId }));
|
||||
if (data.reply && !data.visibleUsers.some(x => x.id === data.reply?.userId)) {
|
||||
data.visibleUsers.push(await Users.findOneByOrFail({ id: data.reply.userId }));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,7 +236,7 @@ export default async (user: { id: User['id']; username: User['username']; host:
|
|||
|
||||
res(note);
|
||||
|
||||
// 統計を更新
|
||||
// Update Statistics
|
||||
notesChart.update(note, true);
|
||||
perUserNotesChart.update(user, note, true);
|
||||
|
||||
|
@ -247,7 +248,7 @@ export default async (user: { id: User['id']; username: User['username']; host:
|
|||
});
|
||||
}
|
||||
|
||||
// ハッシュタグ更新
|
||||
// Hashtag Update
|
||||
if (data.visibility === 'public' || data.visibility === 'home') {
|
||||
updateHashtags(user, tags);
|
||||
}
|
||||
|
@ -301,7 +302,7 @@ export default async (user: { id: User['id']; username: User['username']; host:
|
|||
saveReply(data.reply, note);
|
||||
}
|
||||
|
||||
// この投稿を除く指定したユーザーによる指定したノートのリノートが存在しないとき
|
||||
// When there is no re-note of the specified note by the specified user except for this post
|
||||
if (data.renote && (await countSameRenotes(user.id, data.renote.id, note.id) === 0)) {
|
||||
incRenoteCount(data.renote);
|
||||
}
|
||||
|
@ -319,12 +320,12 @@ export default async (user: { id: User['id']; username: User['username']; host:
|
|||
if (!silent) {
|
||||
if (Users.isLocalUser(user)) activeUsersChart.write(user);
|
||||
|
||||
// 未読通知を作成
|
||||
// Create unread notifications
|
||||
if (data.visibility === 'specified') {
|
||||
if (data.visibleUsers == null) throw new Error('invalid param');
|
||||
|
||||
for (const u of data.visibleUsers) {
|
||||
// ローカルユーザーのみ
|
||||
// Local users only
|
||||
if (!Users.isLocalUser(u)) continue;
|
||||
|
||||
insertNoteUnread(u.id, note, {
|
||||
|
@ -334,7 +335,7 @@ export default async (user: { id: User['id']; username: User['username']; host:
|
|||
}
|
||||
} else {
|
||||
for (const u of mentionedUsers) {
|
||||
// ローカルユーザーのみ
|
||||
// Local users only
|
||||
if (!Users.isLocalUser(u)) continue;
|
||||
|
||||
insertNoteUnread(u.id, note, {
|
||||
|
@ -423,24 +424,24 @@ export default async (user: { id: User['id']; username: User['username']; host:
|
|||
const noteActivity = await renderNoteOrRenoteActivity(data, note);
|
||||
const dm = new DeliverManager(user, noteActivity);
|
||||
|
||||
// メンションされたリモートユーザーに配送
|
||||
// Delivered to remote users who have been mentioned
|
||||
for (const u of mentionedUsers.filter(u => Users.isRemoteUser(u))) {
|
||||
dm.addDirectRecipe(u as IRemoteUser);
|
||||
}
|
||||
|
||||
// 投稿がリプライかつ投稿者がローカルユーザーかつリプライ先の投稿の投稿者がリモートユーザーなら配送
|
||||
// If the post is a reply and the poster is a local user and the poster of the post to which you are replying is a remote user, deliver
|
||||
if (data.reply && data.reply.userHost !== null) {
|
||||
const u = await Users.findOneBy({ id: data.reply.userId });
|
||||
if (u && Users.isRemoteUser(u)) dm.addDirectRecipe(u);
|
||||
}
|
||||
|
||||
// 投稿がRenoteかつ投稿者がローカルユーザーかつRenote元の投稿の投稿者がリモートユーザーなら配送
|
||||
// If the post is a Renote and the poster is a local user and the poster of the original Renote post is a remote user, deliver
|
||||
if (data.renote && data.renote.userHost !== null) {
|
||||
const u = await Users.findOneBy({ id: data.renote.userId });
|
||||
if (u && Users.isRemoteUser(u)) dm.addDirectRecipe(u);
|
||||
}
|
||||
|
||||
// フォロワーに配送
|
||||
// Deliver to followers
|
||||
if (['public', 'home', 'followers'].includes(note.visibility)) {
|
||||
dm.addFollowersRecipe();
|
||||
}
|
||||
|
@ -461,23 +462,23 @@ export default async (user: { id: User['id']; username: User['username']; host:
|
|||
lastNotedAt: new Date(),
|
||||
});
|
||||
|
||||
Notes.countBy({
|
||||
const count = await Notes.countBy({
|
||||
userId: user.id,
|
||||
channelId: data.channel.id,
|
||||
}).then(count => {
|
||||
// この処理が行われるのはノート作成後なので、ノートが一つしかなかったら最初の投稿だと判断できる
|
||||
// TODO: とはいえノートを削除して何回も投稿すればその分だけインクリメントされる雑さもあるのでどうにかしたい
|
||||
if (count === 1) {
|
||||
Channels.increment({ id: data.channel!.id }, 'usersCount', 1);
|
||||
}
|
||||
});
|
||||
|
||||
// This process takes place after the note is created, so if there is only one note, you can determine that it is the first submission.
|
||||
// TODO: but there's also the messiness of deleting a note and posting it multiple times, which is incremented by the number of times it's posted, so I'd like to do something about that.
|
||||
if (count === 1) {
|
||||
Channels.increment({ id: data.channel.id }, 'usersCount', 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Register to search database
|
||||
index(note);
|
||||
});
|
||||
|
||||
async function renderNoteOrRenoteActivity(data: Option, note: Note) {
|
||||
async function renderNoteOrRenoteActivity(data: Option, note: Note): Promise<IActivity | null> {
|
||||
if (data.localOnly) return null;
|
||||
|
||||
const content = data.renote && data.text == null && data.poll == null && (data.files == null || data.files.length === 0)
|
||||
|
@ -487,7 +488,7 @@ async function renderNoteOrRenoteActivity(data: Option, note: Note) {
|
|||
return renderActivity(content);
|
||||
}
|
||||
|
||||
function incRenoteCount(renote: Note) {
|
||||
function incRenoteCount(renote: Note): void {
|
||||
Notes.createQueryBuilder().update()
|
||||
.set({
|
||||
renoteCount: () => '"renoteCount" + 1',
|
||||
|
@ -497,19 +498,17 @@ function incRenoteCount(renote: Note) {
|
|||
.execute();
|
||||
}
|
||||
|
||||
async function insertNote(user: { id: User['id']; host: User['host']; }, data: Option, tags: string[], emojis: string[], mentionedUsers: MinimumUser[]) {
|
||||
async function insertNote(user: { id: User['id']; host: User['host']; }, data: Option, tags: string[], emojis: string[], mentionedUsers: MinimumUser[]): Promise<Note> {
|
||||
const createdAt = data.createdAt ?? new Date();
|
||||
|
||||
const insert = new Note({
|
||||
id: genId(data.createdAt!),
|
||||
createdAt: data.createdAt!,
|
||||
fileIds: data.files ? data.files.map(file => file.id) : [],
|
||||
replyId: data.reply ? data.reply.id : null,
|
||||
renoteId: data.renote ? data.renote.id : null,
|
||||
channelId: data.channel ? data.channel.id : null,
|
||||
threadId: data.reply
|
||||
? data.reply.threadId
|
||||
? data.reply.threadId
|
||||
: data.reply.id
|
||||
: null,
|
||||
id: genId(createdAt),
|
||||
createdAt,
|
||||
fileIds: data.files?.map(file => file.id) ?? [],
|
||||
replyId: data.reply?.id ?? null,
|
||||
renoteId: data.renote?.id ?? null,
|
||||
channelId: data.channel?.id ?? null,
|
||||
threadId: data.reply?.threadId ?? data.reply?.id ?? null,
|
||||
name: data.name,
|
||||
text: data.text,
|
||||
hasPoll: data.poll != null,
|
||||
|
@ -517,15 +516,13 @@ async function insertNote(user: { id: User['id']; host: User['host']; }, data: O
|
|||
tags: tags.map(tag => normalizeForSearch(tag)),
|
||||
emojis,
|
||||
userId: user.id,
|
||||
localOnly: data.localOnly!,
|
||||
visibility: data.visibility as any,
|
||||
localOnly: data.localOnly ?? false,
|
||||
visibility: data.visibility,
|
||||
visibleUserIds: data.visibility === 'specified'
|
||||
? data.visibleUsers
|
||||
? data.visibleUsers.map(u => u.id)
|
||||
: []
|
||||
? data.visibleUsers?.map(u => u.id) ?? []
|
||||
: [],
|
||||
|
||||
attachedFileTypes: data.files ? data.files.map(file => file.type) : [],
|
||||
attachedFileTypes: data.files?.map(file => file.type) ?? [],
|
||||
|
||||
// denormalized data below
|
||||
replyUserId: data.reply?.userId,
|
||||
|
@ -543,29 +540,26 @@ async function insertNote(user: { id: User['id']; host: User['host']; }, data: O
|
|||
insert.mentions = mentionedUsers.map(u => u.id);
|
||||
}
|
||||
|
||||
// 投稿を作成
|
||||
// Create a post
|
||||
try {
|
||||
if (insert.hasPoll) {
|
||||
// Start transaction
|
||||
await db.transaction(async transactionalEntityManager => {
|
||||
await transactionalEntityManager.insert(Note, insert);
|
||||
// Start transaction
|
||||
await db.transaction(async transactionalEntityManager => {
|
||||
await transactionalEntityManager.insert(Note, insert);
|
||||
|
||||
if (data.poll != null) {
|
||||
const poll = new Poll({
|
||||
noteId: insert.id,
|
||||
choices: data.poll!.choices,
|
||||
expiresAt: data.poll!.expiresAt,
|
||||
multiple: data.poll!.multiple,
|
||||
votes: new Array(data.poll!.choices.length).fill(0),
|
||||
choices: data.poll.choices,
|
||||
expiresAt: data.poll.expiresAt,
|
||||
multiple: data.poll.multiple,
|
||||
votes: new Array(data.poll.choices.length).fill(0),
|
||||
noteVisibility: insert.visibility,
|
||||
userId: user.id,
|
||||
userHost: user.host,
|
||||
});
|
||||
|
||||
await transactionalEntityManager.insert(Poll, poll);
|
||||
});
|
||||
} else {
|
||||
await Notes.insert(insert);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return insert;
|
||||
} catch (e) {
|
||||
|
@ -582,10 +576,10 @@ async function insertNote(user: { id: User['id']; host: User['host']; }, data: O
|
|||
}
|
||||
}
|
||||
|
||||
function index(note: Note) {
|
||||
function index(note: Note): void {
|
||||
if (note.text == null || config.elasticsearch == null) return;
|
||||
|
||||
es!.index({
|
||||
es.index({
|
||||
index: config.elasticsearch.index || 'misskey_note',
|
||||
id: note.id.toString(),
|
||||
body: {
|
||||
|
@ -596,7 +590,7 @@ function index(note: Note) {
|
|||
});
|
||||
}
|
||||
|
||||
async function notifyToWatchersOfRenotee(renote: Note, user: { id: User['id']; }, nm: NotificationManager, type: NotificationType) {
|
||||
async function notifyToWatchersOfRenotee(renote: Note, user: { id: User['id']; }, nm: NotificationManager, type: NotificationType): Promise<void> {
|
||||
const watchers = await NoteWatchings.findBy({
|
||||
noteId: renote.id,
|
||||
userId: Not(user.id),
|
||||
|
@ -607,7 +601,7 @@ async function notifyToWatchersOfRenotee(renote: Note, user: { id: User['id']; }
|
|||
}
|
||||
}
|
||||
|
||||
async function notifyToWatchersOfReplyee(reply: Note, user: { id: User['id']; }, nm: NotificationManager) {
|
||||
async function notifyToWatchersOfReplyee(reply: Note, user: { id: User['id']; }, nm: NotificationManager): Promise<void> {
|
||||
const watchers = await NoteWatchings.findBy({
|
||||
noteId: reply.id,
|
||||
userId: Not(user.id),
|
||||
|
@ -618,7 +612,7 @@ async function notifyToWatchersOfReplyee(reply: Note, user: { id: User['id']; },
|
|||
}
|
||||
}
|
||||
|
||||
async function createMentionedEvents(mentionedUsers: MinimumUser[], note: Note, nm: NotificationManager) {
|
||||
async function createMentionedEvents(mentionedUsers: MinimumUser[], note: Note, nm: NotificationManager): Promise<void> {
|
||||
for (const u of mentionedUsers.filter(u => Users.isLocalUser(u))) {
|
||||
const threadMuted = await NoteThreadMutings.findOneBy({
|
||||
userId: u.id,
|
||||
|
@ -653,11 +647,11 @@ async function createMentionedEvents(mentionedUsers: MinimumUser[], note: Note,
|
|||
}
|
||||
}
|
||||
|
||||
function saveReply(reply: Note, note: Note) {
|
||||
function saveReply(reply: Note, note: Note): void {
|
||||
Notes.increment({ id: reply.id }, 'repliesCount', 1);
|
||||
}
|
||||
|
||||
function incNotesCountOfUser(user: { id: User['id']; }) {
|
||||
function incNotesCountOfUser(user: { id: User['id']; }): void {
|
||||
Users.createQueryBuilder().update()
|
||||
.set({
|
||||
updatedAt: new Date(),
|
||||
|
@ -668,7 +662,7 @@ function incNotesCountOfUser(user: { id: User['id']; }) {
|
|||
}
|
||||
|
||||
async function extractMentionedUsers(user: { host: User['host']; }, tokens: mfm.MfmNode[]): Promise<User[]> {
|
||||
if (tokens == null) return [];
|
||||
if (tokens.length === 0) return [];
|
||||
|
||||
const mentions = extractMentions(tokens);
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Brackets, In, IsNull, Not } from 'typeorm';
|
||||
import { Brackets, FindOptionsWhere, In, IsNull, Not } from 'typeorm';
|
||||
import { publishNoteStream } from '@/services/stream.js';
|
||||
import renderDelete from '@/remote/activitypub/renderer/delete.js';
|
||||
import renderAnnounce from '@/remote/activitypub/renderer/announce.js';
|
||||
|
@ -41,10 +41,12 @@ export default async function(user: { id: User['id']; uri: User['uri']; host: Us
|
|||
if (Users.isLocalUser(user) && !note.localOnly) {
|
||||
let renote: Note | null = null;
|
||||
|
||||
// if deletd note is renote
|
||||
// if deleted note is renote
|
||||
if (isPureRenote(note)) {
|
||||
renote = await Notes.findOneBy({
|
||||
id: note.renoteId,
|
||||
// isPureRenote checks if note.renoteId is null already, so renoteId should be non-null.
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
id: note.renoteId!,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -106,7 +108,7 @@ async function findCascadingNotes(note: Note): Promise<Note[]> {
|
|||
}
|
||||
|
||||
async function getMentionedRemoteUsers(note: Note): Promise<IRemoteUser[]> {
|
||||
const where = [] as any[];
|
||||
const where: FindOptionsWhere<User>[] = [];
|
||||
|
||||
// mention / reply / dm
|
||||
if (note.mentions.length > 0) {
|
||||
|
|
|
@ -6,7 +6,7 @@ import { PollVotes, NoteWatchings, Polls, Blockings, NoteThreadMutings } from '@
|
|||
import { genId } from '@/misc/gen-id.js';
|
||||
import { createNotification } from '@/services/create-notification.js';
|
||||
|
||||
export default async function(user: CacheableUser, note: Note, choice: number) {
|
||||
export async function vote(user: CacheableUser, note: Note, choice: number): Promise<void> {
|
||||
const poll = await Polls.findOneBy({ noteId: note.id });
|
||||
|
||||
if (poll == null) throw new Error('poll not found');
|
||||
|
|
|
@ -13,9 +13,9 @@ import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error.js
|
|||
import { NoteReaction } from '@/models/entities/note-reaction.js';
|
||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||
import { createNotification } from '@/services/create-notification.js';
|
||||
import deleteReaction from './delete.js';
|
||||
import { deleteReaction } from './delete.js';
|
||||
|
||||
export default async (user: { id: User['id']; host: User['host']; }, note: Note, reaction?: string) => {
|
||||
export async function createReaction(user: { id: User['id']; host: User['host']; }, note: Note, reaction?: string): Promise<void> {
|
||||
// Check blocking
|
||||
if (note.userId !== user.id) {
|
||||
const block = await Blockings.findOneBy({
|
||||
|
@ -148,4 +148,4 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note,
|
|||
dm.execute();
|
||||
}
|
||||
//#endregion
|
||||
};
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import { Note } from '@/models/entities/note.js';
|
|||
import { NoteReactions, Users, Notes } from '@/models/index.js';
|
||||
import { decodeReaction } from '@/misc/reaction-lib.js';
|
||||
|
||||
export default async (user: { id: User['id']; host: User['host']; }, note: Note) => {
|
||||
export async function deleteReaction(user: { id: User['id']; host: User['host']; }, note: Note): Promise<void> {
|
||||
// if already unreacted
|
||||
const exist = await NoteReactions.findOneBy({
|
||||
noteId: note.id,
|
||||
|
@ -55,4 +55,4 @@ export default async (user: { id: User['id']; host: User['host']; }, note: Note)
|
|||
dm.execute();
|
||||
}
|
||||
//#endregion
|
||||
};
|
||||
}
|
||||
|
|
|
@ -12,14 +12,14 @@ import { Packed } from '@/misc/schema.js';
|
|||
/**
|
||||
* Mark notes as read
|
||||
*/
|
||||
export default async function(
|
||||
export async function readNote(
|
||||
userId: User['id'],
|
||||
notes: (Note | Packed<'Note'>)[],
|
||||
info?: {
|
||||
following: Set<User['id']>;
|
||||
followingChannels: Set<Channel['id']>;
|
||||
},
|
||||
) {
|
||||
): Promise<void> {
|
||||
const following = info?.following ? info.following : new Set<string>((await Followings.find({
|
||||
where: {
|
||||
followerId: userId,
|
||||
|
|
|
@ -2,9 +2,9 @@ import { User } from '@/models/entities/user.js';
|
|||
import { NoteWatchings } from '@/models/index.js';
|
||||
import { Note } from '@/models/entities/note.js';
|
||||
|
||||
export default async (me: User['id'], note: Note) => {
|
||||
export async function unwatch(me: User['id'], note: Note): Promise<void> {
|
||||
await NoteWatchings.delete({
|
||||
noteId: note.id,
|
||||
userId: me,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ import { NoteWatchings } from '@/models/index.js';
|
|||
import { genId } from '@/misc/gen-id.js';
|
||||
import { NoteWatching } from '@/models/entities/note-watching.js';
|
||||
|
||||
export default async (me: User['id'], note: Note) => {
|
||||
// 自分の投稿はwatchできない
|
||||
export async function watch(me: User['id'], note: Note): Promise<void> {
|
||||
// User can't watch their own posts.
|
||||
if (me === note.userId) {
|
||||
return;
|
||||
}
|
||||
|
@ -17,4 +17,4 @@ export default async (me: User['id'], note: Note) => {
|
|||
userId: me,
|
||||
noteUserId: note.userId,
|
||||
} as NoteWatching);
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue