mirror of
https://github.com/paricafe/misskey.git
synced 2024-11-24 08:16:44 -06:00
commit
9d8f9353e4
13 changed files with 142 additions and 43 deletions
|
@ -136,13 +136,17 @@ export class AntennaService implements OnApplicationShutdown {
|
||||||
const { username, host } = Acct.parse(x);
|
const { username, host } = Acct.parse(x);
|
||||||
return this.utilityService.getFullApAccount(username, host).toLowerCase();
|
return this.utilityService.getFullApAccount(username, host).toLowerCase();
|
||||||
});
|
});
|
||||||
if (!accts.includes(this.utilityService.getFullApAccount(noteUser.username, noteUser.host).toLowerCase())) return false;
|
const matchUser = this.utilityService.getFullApAccount(noteUser.username, noteUser.host).toLowerCase();
|
||||||
|
const matchWildcard = this.utilityService.getFullApAccount('*', noteUser.host).toLowerCase();
|
||||||
|
if (!accts.includes(matchUser) && !accts.includes(matchWildcard)) return false;
|
||||||
} else if (antenna.src === 'users_blacklist') {
|
} else if (antenna.src === 'users_blacklist') {
|
||||||
const accts = antenna.users.map(x => {
|
const accts = antenna.users.map(x => {
|
||||||
const { username, host } = Acct.parse(x);
|
const { username, host } = Acct.parse(x);
|
||||||
return this.utilityService.getFullApAccount(username, host).toLowerCase();
|
return this.utilityService.getFullApAccount(username, host).toLowerCase();
|
||||||
});
|
});
|
||||||
if (accts.includes(this.utilityService.getFullApAccount(noteUser.username, noteUser.host).toLowerCase())) return false;
|
const matchUser = this.utilityService.getFullApAccount(noteUser.username, noteUser.host).toLowerCase();
|
||||||
|
const matchWildcard = this.utilityService.getFullApAccount('*', noteUser.host).toLowerCase();
|
||||||
|
if (accts.includes(matchUser) || accts.includes(matchWildcard)) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const keywords = antenna.keywords
|
const keywords = antenna.keywords
|
||||||
|
|
|
@ -227,25 +227,33 @@ export class DriveService {
|
||||||
const thumbnailAccessKey = 'thumbnail-' + randomUUID();
|
const thumbnailAccessKey = 'thumbnail-' + randomUUID();
|
||||||
const webpublicAccessKey = 'webpublic-' + randomUUID();
|
const webpublicAccessKey = 'webpublic-' + randomUUID();
|
||||||
|
|
||||||
const url = this.internalStorageService.saveFromPath(accessKey, path);
|
// Ugly type is just to help TS figure out that 2nd / 3rd promises are optional.
|
||||||
|
const promises: [Promise<string>, ...(Promise<string> | undefined)[]] = [
|
||||||
let thumbnailUrl: string | null = null;
|
this.internalStorageService.saveFromPath(accessKey, path),
|
||||||
let webpublicUrl: string | null = null;
|
];
|
||||||
|
|
||||||
if (alts.thumbnail) {
|
if (alts.thumbnail) {
|
||||||
thumbnailUrl = this.internalStorageService.saveFromBuffer(thumbnailAccessKey, alts.thumbnail.data);
|
promises.push(this.internalStorageService.saveFromBuffer(thumbnailAccessKey, alts.thumbnail.data));
|
||||||
this.registerLogger.info(`thumbnail stored: ${thumbnailAccessKey}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alts.webpublic) {
|
if (alts.webpublic) {
|
||||||
webpublicUrl = this.internalStorageService.saveFromBuffer(webpublicAccessKey, alts.webpublic.data);
|
promises.push(this.internalStorageService.saveFromBuffer(webpublicAccessKey, alts.webpublic.data));
|
||||||
|
}
|
||||||
|
|
||||||
|
const [url, thumbnailUrl, webpublicUrl] = await Promise.all(promises);
|
||||||
|
|
||||||
|
if (thumbnailUrl) {
|
||||||
|
this.registerLogger.info(`thumbnail stored: ${thumbnailAccessKey}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (webpublicUrl) {
|
||||||
this.registerLogger.info(`web stored: ${webpublicAccessKey}`);
|
this.registerLogger.info(`web stored: ${webpublicAccessKey}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
file.storedInternal = true;
|
file.storedInternal = true;
|
||||||
file.url = url;
|
file.url = url;
|
||||||
file.thumbnailUrl = thumbnailUrl;
|
file.thumbnailUrl = thumbnailUrl ?? null;
|
||||||
file.webpublicUrl = webpublicUrl;
|
file.webpublicUrl = webpublicUrl ?? null;
|
||||||
file.accessKey = accessKey;
|
file.accessKey = accessKey;
|
||||||
file.thumbnailAccessKey = thumbnailAccessKey;
|
file.thumbnailAccessKey = thumbnailAccessKey;
|
||||||
file.webpublicAccessKey = webpublicAccessKey;
|
file.webpublicAccessKey = webpublicAccessKey;
|
||||||
|
@ -741,19 +749,19 @@ export class DriveService {
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async deleteFileSync(file: MiDriveFile, isExpired = false, deleter?: MiUser) {
|
public async deleteFileSync(file: MiDriveFile, isExpired = false, deleter?: MiUser) {
|
||||||
|
const promises = [];
|
||||||
|
|
||||||
if (file.storedInternal) {
|
if (file.storedInternal) {
|
||||||
this.internalStorageService.del(file.accessKey!);
|
promises.push(this.internalStorageService.del(file.accessKey!));
|
||||||
|
|
||||||
if (file.thumbnailUrl) {
|
if (file.thumbnailUrl) {
|
||||||
this.internalStorageService.del(file.thumbnailAccessKey!);
|
promises.push(this.internalStorageService.del(file.thumbnailAccessKey!));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file.webpublicUrl) {
|
if (file.webpublicUrl) {
|
||||||
this.internalStorageService.del(file.webpublicAccessKey!);
|
promises.push(this.internalStorageService.del(file.webpublicAccessKey!));
|
||||||
}
|
}
|
||||||
} else if (!file.isLink) {
|
} else if (!file.isLink) {
|
||||||
const promises = [];
|
|
||||||
|
|
||||||
promises.push(this.deleteObjectStorageFile(file.accessKey!));
|
promises.push(this.deleteObjectStorageFile(file.accessKey!));
|
||||||
|
|
||||||
if (file.thumbnailUrl) {
|
if (file.thumbnailUrl) {
|
||||||
|
@ -763,10 +771,10 @@ export class DriveService {
|
||||||
if (file.webpublicUrl) {
|
if (file.webpublicUrl) {
|
||||||
promises.push(this.deleteObjectStorageFile(file.webpublicAccessKey!));
|
promises.push(this.deleteObjectStorageFile(file.webpublicAccessKey!));
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(promises);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await Promise.all(promises);
|
||||||
|
|
||||||
this.deletePostProcess(file, isExpired, deleter);
|
this.deletePostProcess(file, isExpired, deleter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -138,6 +138,10 @@ export interface NoteEventTypes {
|
||||||
reaction: string;
|
reaction: string;
|
||||||
userId: MiUser['id'];
|
userId: MiUser['id'];
|
||||||
};
|
};
|
||||||
|
replied: {
|
||||||
|
id: MiNote['id'];
|
||||||
|
userId: MiUser['id'];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
type NoteStreamEventTypes = {
|
type NoteStreamEventTypes = {
|
||||||
[key in keyof NoteEventTypes]: {
|
[key in keyof NoteEventTypes]: {
|
||||||
|
|
|
@ -52,8 +52,10 @@ import { FeaturedService } from '@/core/FeaturedService.js';
|
||||||
import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
|
import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
|
||||||
import { UtilityService } from '@/core/UtilityService.js';
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import { UserBlockingService } from '@/core/UserBlockingService.js';
|
import { UserBlockingService } from '@/core/UserBlockingService.js';
|
||||||
|
import { CacheService } from '@/core/CacheService.js';
|
||||||
import { isReply } from '@/misc/is-reply.js';
|
import { isReply } from '@/misc/is-reply.js';
|
||||||
import { trackPromise } from '@/misc/promise-tracker.js';
|
import { trackPromise } from '@/misc/promise-tracker.js';
|
||||||
|
import { isUserRelated } from '@/misc/is-user-related.js';
|
||||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
import { CollapsedQueue } from '@/misc/collapsed-queue.js';
|
import { CollapsedQueue } from '@/misc/collapsed-queue.js';
|
||||||
|
|
||||||
|
@ -217,6 +219,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
private instanceChart: InstanceChart,
|
private instanceChart: InstanceChart,
|
||||||
private utilityService: UtilityService,
|
private utilityService: UtilityService,
|
||||||
private userBlockingService: UserBlockingService,
|
private userBlockingService: UserBlockingService,
|
||||||
|
private cacheService: CacheService,
|
||||||
) {
|
) {
|
||||||
this.updateNotesCountQueue = new CollapsedQueue(process.env.NODE_ENV !== 'test' ? 60 * 1000 * 5 : 0, this.collapseNotesCount, this.performUpdateNotesCount);
|
this.updateNotesCountQueue = new CollapsedQueue(process.env.NODE_ENV !== 'test' ? 60 * 1000 * 5 : 0, this.collapseNotesCount, this.performUpdateNotesCount);
|
||||||
}
|
}
|
||||||
|
@ -450,6 +453,14 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
userHost: user.host,
|
userHost: user.host,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// should really not happen, but better safe than sorry
|
||||||
|
if (data.reply?.id === insert.id) {
|
||||||
|
throw new Error("A note can't reply to itself");
|
||||||
|
}
|
||||||
|
if (data.renote?.id === insert.id) {
|
||||||
|
throw new Error("A note can't renote itself");
|
||||||
|
}
|
||||||
|
|
||||||
if (data.uri != null) insert.uri = data.uri;
|
if (data.uri != null) insert.uri = data.uri;
|
||||||
if (data.url != null) insert.url = data.url;
|
if (data.url != null) insert.url = data.url;
|
||||||
|
|
||||||
|
@ -630,6 +641,10 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
|
|
||||||
// If has in reply to note
|
// If has in reply to note
|
||||||
if (data.reply) {
|
if (data.reply) {
|
||||||
|
this.globalEventService.publishNoteStream(data.reply.id, 'replied', {
|
||||||
|
id: note.id,
|
||||||
|
userId: user.id,
|
||||||
|
});
|
||||||
// 通知
|
// 通知
|
||||||
if (data.reply.userHost === null) {
|
if (data.reply.userHost === null) {
|
||||||
const isThreadMuted = await this.noteThreadMutingsRepository.exists({
|
const isThreadMuted = await this.noteThreadMutingsRepository.exists({
|
||||||
|
@ -639,7 +654,15 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!isThreadMuted) {
|
const [
|
||||||
|
userIdsWhoMeMuting,
|
||||||
|
] = data.reply.userId ? await Promise.all([
|
||||||
|
this.cacheService.userMutingsCache.fetch(data.reply.userId),
|
||||||
|
]) : [new Set<string>()];
|
||||||
|
|
||||||
|
const muted = isUserRelated(note, userIdsWhoMeMuting);
|
||||||
|
|
||||||
|
if (!isThreadMuted && !muted) {
|
||||||
nm.push(data.reply.userId, 'reply');
|
nm.push(data.reply.userId, 'reply');
|
||||||
this.globalEventService.publishMainStream(data.reply.userId, 'reply', noteObj);
|
this.globalEventService.publishMainStream(data.reply.userId, 'reply', noteObj);
|
||||||
|
|
||||||
|
@ -659,7 +682,24 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
|
|
||||||
// Notify
|
// Notify
|
||||||
if (data.renote.userHost === null) {
|
if (data.renote.userHost === null) {
|
||||||
nm.push(data.renote.userId, type);
|
const isThreadMuted = await this.noteThreadMutingsRepository.exists({
|
||||||
|
where: {
|
||||||
|
userId: data.renote.userId,
|
||||||
|
threadId: data.renote.threadId ?? data.renote.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const [
|
||||||
|
userIdsWhoMeMuting,
|
||||||
|
] = data.renote.userId ? await Promise.all([
|
||||||
|
this.cacheService.userMutingsCache.fetch(data.renote.userId),
|
||||||
|
]) : [new Set<string>()];
|
||||||
|
|
||||||
|
const muted = isUserRelated(note, userIdsWhoMeMuting);
|
||||||
|
|
||||||
|
if (!isThreadMuted && !muted) {
|
||||||
|
nm.push(data.renote.userId, type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Publish event
|
// Publish event
|
||||||
|
@ -788,7 +828,15 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isThreadMuted) {
|
const [
|
||||||
|
userIdsWhoMeMuting,
|
||||||
|
] = u.id ? await Promise.all([
|
||||||
|
this.cacheService.userMutingsCache.fetch(u.id),
|
||||||
|
]) : [new Set<string>()];
|
||||||
|
|
||||||
|
const muted = isUserRelated(note, userIdsWhoMeMuting);
|
||||||
|
|
||||||
|
if (isThreadMuted || muted) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,13 @@ export class NoteDeleteService {
|
||||||
await this.notesRepository.decrement({ id: note.replyId }, 'repliesCount', 1);
|
await this.notesRepository.decrement({ id: note.replyId }, 'repliesCount', 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (note.renoteId && note.text == null && !note.hasPoll && (note.fileIds == null || note.fileIds.length === 0)) {
|
||||||
|
await this.notesRepository.findOneBy({ id: note.renoteId }).then(async (renote) => {
|
||||||
|
if (!renote) return;
|
||||||
|
if (renote.userId !== user.id) await this.notesRepository.decrement({ id: renote.id }, 'renoteCount', 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!quiet) {
|
if (!quiet) {
|
||||||
this.globalEventService.publishNoteStream(note.id, 'deleted', {
|
this.globalEventService.publishNoteStream(note.id, 'deleted', {
|
||||||
deletedAt: deletedAt,
|
deletedAt: deletedAt,
|
||||||
|
@ -106,15 +113,25 @@ export class NoteDeleteService {
|
||||||
this.perUserNotesChart.update(user, note, false);
|
this.perUserNotesChart.update(user, note, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.meta.enableStatsForFederatedInstances) {
|
if (note.renoteId && note.text) {
|
||||||
if (this.userEntityService.isRemoteUser(user)) {
|
// Decrement notes count (user)
|
||||||
this.federatedInstanceService.fetchOrRegister(user.host).then(async i => {
|
this.decNotesCountOfUser(user);
|
||||||
|
} else if (!note.renoteId) {
|
||||||
|
// Decrement notes count (user)
|
||||||
|
this.decNotesCountOfUser(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.userEntityService.isRemoteUser(user)) {
|
||||||
|
this.federatedInstanceService.fetch(user.host).then(async i => {
|
||||||
|
if (note.renoteId && note.text) {
|
||||||
this.instancesRepository.decrement({ id: i.id }, 'notesCount', 1);
|
this.instancesRepository.decrement({ id: i.id }, 'notesCount', 1);
|
||||||
if (this.meta.enableChartsForFederatedInstances) {
|
} else if (!note.renoteId) {
|
||||||
this.instanceChart.updateNote(i.host, note, false);
|
this.instancesRepository.decrement({ id: i.id }, 'notesCount', 1);
|
||||||
}
|
}
|
||||||
});
|
if (this.meta.enableChartsForFederatedInstances) {
|
||||||
}
|
this.instanceChart.updateNote(i.host, note, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,11 @@ export class NoteReadService implements OnApplicationShutdown {
|
||||||
noteUserId: note.userId,
|
noteUserId: note.userId,
|
||||||
};
|
};
|
||||||
|
|
||||||
await this.noteUnreadsRepository.insert(unread);
|
/* we may be called from NoteEditService, for a note that's
|
||||||
|
already present in the `note_unread` table: `upsert` makes sure
|
||||||
|
we don't throw a "duplicate key" error, while still updating
|
||||||
|
the other columns if they've changed */
|
||||||
|
await this.noteUnreadsRepository.upsert(unread, ['userId', 'noteId']);
|
||||||
|
|
||||||
// 2秒経っても既読にならなかったら「未読の投稿がありますよ」イベントを発行する
|
// 2秒経っても既読にならなかったら「未読の投稿がありますよ」イベントを発行する
|
||||||
setTimeout(2000, 'unread note', { signal: this.#shutdownController.signal }).then(async () => {
|
setTimeout(2000, 'unread note', { signal: this.#shutdownController.signal }).then(async () => {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { EmojisRepository, NoteReactionsRepository, UsersRepository, NotesRepository, MiMeta } from '@/models/_.js';
|
import type { EmojisRepository, NoteReactionsRepository, UsersRepository, NotesRepository, NoteThreadMutingsRepository, MiMeta } from '@/models/_.js';
|
||||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
import type { MiRemoteUser, MiUser } from '@/models/User.js';
|
import type { MiRemoteUser, MiUser } from '@/models/User.js';
|
||||||
import type { MiNote } from '@/models/Note.js';
|
import type { MiNote } from '@/models/Note.js';
|
||||||
|
@ -64,8 +64,8 @@ type DecodedReaction = {
|
||||||
host?: string | null;
|
host?: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const isCustomEmojiRegexp = /^:([\w+-]+)(?:@\.)?:$/;
|
const isCustomEmojiRegexp = /^:([\p{Letter}\p{Number}\p{Mark}_+-]+)(?:@\.)?:$/u;
|
||||||
const decodeCustomEmojiRegexp = /^:([\w+-]+)(?:@([\w.-]+))?:$/;
|
const decodeCustomEmojiRegexp = /^:([\p{Letter}\p{Number}\p{Mark}_+-]+)(?:@([\w.-]+))?:$/u;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ReactionService {
|
export class ReactionService {
|
||||||
|
@ -82,6 +82,9 @@ export class ReactionService {
|
||||||
@Inject(DI.noteReactionsRepository)
|
@Inject(DI.noteReactionsRepository)
|
||||||
private noteReactionsRepository: NoteReactionsRepository,
|
private noteReactionsRepository: NoteReactionsRepository,
|
||||||
|
|
||||||
|
@Inject(DI.noteThreadMutingsRepository)
|
||||||
|
private noteThreadMutingsRepository: NoteThreadMutingsRepository,
|
||||||
|
|
||||||
@Inject(DI.emojisRepository)
|
@Inject(DI.emojisRepository)
|
||||||
private emojisRepository: EmojisRepository,
|
private emojisRepository: EmojisRepository,
|
||||||
|
|
||||||
|
@ -256,10 +259,19 @@ export class ReactionService {
|
||||||
|
|
||||||
// リアクションされたユーザーがローカルユーザーなら通知を作成
|
// リアクションされたユーザーがローカルユーザーなら通知を作成
|
||||||
if (note.userHost === null) {
|
if (note.userHost === null) {
|
||||||
this.notificationService.createNotification(note.userId, 'reaction', {
|
const isThreadMuted = await this.noteThreadMutingsRepository.exists({
|
||||||
noteId: note.id,
|
where: {
|
||||||
reaction: reaction,
|
userId: note.userId,
|
||||||
}, user.id);
|
threadId: note.threadId ?? note.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isThreadMuted) {
|
||||||
|
this.notificationService.createNotification(note.userId, 'reaction', {
|
||||||
|
noteId: note.id,
|
||||||
|
reaction: reaction,
|
||||||
|
}, user.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region 配信
|
//#region 配信
|
||||||
|
|
|
@ -38,6 +38,7 @@ export class UserSuspendService {
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async suspend(user: MiUser, moderator: MiUser): Promise<void> {
|
public async suspend(user: MiUser, moderator: MiUser): Promise<void> {
|
||||||
|
|
||||||
await this.usersRepository.update(user.id, {
|
await this.usersRepository.update(user.id, {
|
||||||
isSuspended: true,
|
isSuspended: true,
|
||||||
});
|
});
|
||||||
|
|
|
@ -35,7 +35,7 @@ export class ApMfmService {
|
||||||
noMisskeyContent = true;
|
noMisskeyContent = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = this.mfmService.toHtml(parsed, JSON.parse(note.mentionedRemoteUsers));
|
const content = this.mfmService.toHtml(parsed, note.mentionedRemoteUsers ? JSON.parse(note.mentionedRemoteUsers) : []);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
content,
|
content,
|
||||||
|
|
|
@ -16,12 +16,12 @@ import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { LoggerService } from '@/core/LoggerService.js';
|
import { LoggerService } from '@/core/LoggerService.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { fromTuple } from '@/misc/from-tuple.js';
|
|
||||||
import { isCollectionOrOrderedCollection } from './type.js';
|
import { isCollectionOrOrderedCollection } from './type.js';
|
||||||
import { ApDbResolverService } from './ApDbResolverService.js';
|
import { ApDbResolverService } from './ApDbResolverService.js';
|
||||||
import { ApRendererService } from './ApRendererService.js';
|
import { ApRendererService } from './ApRendererService.js';
|
||||||
import { ApRequestService } from './ApRequestService.js';
|
import { ApRequestService } from './ApRequestService.js';
|
||||||
import type { IObject, ICollection, IOrderedCollection } from './type.js';
|
import type { IObject, ICollection, IOrderedCollection } from './type.js';
|
||||||
|
import { fromTuple } from '@/misc/from-tuple.js';
|
||||||
|
|
||||||
export class Resolver {
|
export class Resolver {
|
||||||
private history: Set<string>;
|
private history: Set<string>;
|
||||||
|
|
|
@ -24,12 +24,12 @@ export const getNoteSummary = (note: Packed<'Note'>): string => {
|
||||||
if (note.cw != null) {
|
if (note.cw != null) {
|
||||||
summary += `CW: ${note.cw}`;
|
summary += `CW: ${note.cw}`;
|
||||||
} else if (note.text) {
|
} else if (note.text) {
|
||||||
summary += note.text ? note.text : '';
|
summary += note.text;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ファイルが添付されているとき
|
// ファイルが添付されているとき
|
||||||
if ((note.files ?? []).length !== 0) {
|
if (note.files && note.files.length !== 0) {
|
||||||
summary += ` (📎${note.files!.length})`;
|
summary += ` (📎${note.files.length})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 投票が添付されているとき
|
// 投票が添付されているとき
|
||||||
|
|
|
@ -16,6 +16,7 @@ export class MiNote {
|
||||||
public id: string;
|
public id: string;
|
||||||
|
|
||||||
@Column('timestamp with time zone', {
|
@Column('timestamp with time zone', {
|
||||||
|
comment: 'The update time of the Note.',
|
||||||
default: null,
|
default: null,
|
||||||
})
|
})
|
||||||
public updatedAt: Date | null;
|
public updatedAt: Date | null;
|
||||||
|
|
|
@ -69,7 +69,7 @@ function getJobInfo(job: Bull.Job | undefined, increment = false): string {
|
||||||
|
|
||||||
// onActiveとかonCompletedのattemptsMadeがなぜか0始まりなのでインクリメントする
|
// onActiveとかonCompletedのattemptsMadeがなぜか0始まりなのでインクリメントする
|
||||||
const currentAttempts = job.attemptsMade + (increment ? 1 : 0);
|
const currentAttempts = job.attemptsMade + (increment ? 1 : 0);
|
||||||
const maxAttempts = job.opts.attempts ?? 0;
|
const maxAttempts = job.opts ? job.opts.attempts : 0;
|
||||||
|
|
||||||
return `id=${job.id} attempts=${currentAttempts}/${maxAttempts} age=${formated}`;
|
return `id=${job.id} attempts=${currentAttempts}/${maxAttempts} age=${formated}`;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue