;
@@ -230,7 +236,7 @@ export type SchemaTypeDef =
p['items']['allOf'] extends ReadonlyArray ? UnionToIntersection>>[] :
never
) :
- p['items'] extends NonNullable ? SchemaTypeDef[] :
+ p['items'] extends NonNullable ? SchemaType[] :
any[]
) :
p['anyOf'] extends ReadonlyArray ? UnionSchemaType & PartialIntersection> :
diff --git a/packages/backend/src/models/AbuseReportNotificationRecipient.ts b/packages/backend/src/models/AbuseReportNotificationRecipient.ts
new file mode 100644
index 0000000000..fbff880afc
--- /dev/null
+++ b/packages/backend/src/models/AbuseReportNotificationRecipient.ts
@@ -0,0 +1,100 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Column, Entity, Index, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm';
+import { MiSystemWebhook } from '@/models/SystemWebhook.js';
+import { MiUserProfile } from '@/models/UserProfile.js';
+import { id } from './util/id.js';
+import { MiUser } from './User.js';
+
+/**
+ * 通報受信時に通知を送信する方法.
+ */
+export type RecipientMethod = 'email' | 'webhook';
+
+@Entity('abuse_report_notification_recipient')
+export class MiAbuseReportNotificationRecipient {
+ @PrimaryColumn(id())
+ public id: string;
+
+ /**
+ * 有効かどうか.
+ */
+ @Index()
+ @Column('boolean', {
+ default: true,
+ })
+ public isActive: boolean;
+
+ /**
+ * 更新日時.
+ */
+ @Column('timestamp with time zone', {
+ default: () => 'CURRENT_TIMESTAMP',
+ })
+ public updatedAt: Date;
+
+ /**
+ * 通知設定名.
+ */
+ @Column('varchar', {
+ length: 255,
+ })
+ public name: string;
+
+ /**
+ * 通知方法.
+ */
+ @Index()
+ @Column('varchar', {
+ length: 64,
+ })
+ public method: RecipientMethod;
+
+ /**
+ * 通知先のユーザID.
+ */
+ @Index()
+ @Column({
+ ...id(),
+ nullable: true,
+ })
+ public userId: MiUser['id'] | null;
+
+ /**
+ * 通知先のユーザ.
+ */
+ @ManyToOne(type => MiUser, {
+ onDelete: 'CASCADE',
+ })
+ @JoinColumn({ name: 'userId', referencedColumnName: 'id', foreignKeyConstraintName: 'FK_abuse_report_notification_recipient_userId1' })
+ public user: MiUser | null;
+
+ /**
+ * 通知先のユーザプロフィール.
+ */
+ @ManyToOne(type => MiUserProfile, {})
+ @JoinColumn({ name: 'userId', referencedColumnName: 'userId', foreignKeyConstraintName: 'FK_abuse_report_notification_recipient_userId2' })
+ public userProfile: MiUserProfile | null;
+
+ /**
+ * 通知先のシステムWebhookId.
+ */
+ @Index()
+ @Column({
+ ...id(),
+ nullable: true,
+ })
+ public systemWebhookId: string | null;
+
+ /**
+ * 通知先のシステムWebhook.
+ */
+ @ManyToOne(type => MiSystemWebhook, {
+ onDelete: 'CASCADE',
+ })
+ @JoinColumn()
+ public systemWebhook: MiSystemWebhook | null;
+}
diff --git a/packages/backend/src/models/Antenna.ts b/packages/backend/src/models/Antenna.ts
index 3261d2e6a4..98b43a3347 100644
--- a/packages/backend/src/models/Antenna.ts
+++ b/packages/backend/src/models/Antenna.ts
@@ -103,9 +103,6 @@ export class MiAntenna {
})
public expression: string | null;
- @Column('boolean')
- public notify: boolean;
-
@Index()
@Column('boolean', {
default: true,
diff --git a/packages/backend/src/models/Instance.ts b/packages/backend/src/models/Instance.ts
index 9863c9d75d..17cd5c6665 100644
--- a/packages/backend/src/models/Instance.ts
+++ b/packages/backend/src/models/Instance.ts
@@ -81,13 +81,22 @@ export class MiInstance {
public isNotResponding: boolean;
/**
- * このインスタンスへの配信を停止するか
+ * このインスタンスと不通になった日時
+ */
+ @Column('timestamp with time zone', {
+ nullable: true,
+ })
+ public notRespondingSince: Date | null;
+
+ /**
+ * このインスタンスへの配信状態
*/
@Index()
- @Column('boolean', {
- default: false,
+ @Column('enum', {
+ default: 'none',
+ enum: ['none', 'manuallySuspended', 'goneSuspended', 'autoSuspendedForNotResponding'],
})
- public isSuspended: boolean;
+ public suspensionState: 'none' | 'manuallySuspended' | 'goneSuspended' | 'autoSuspendedForNotResponding';
@Column('varchar', {
length: 64, nullable: true,
diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts
index 91e16f05de..71cafb9cda 100644
--- a/packages/backend/src/models/Meta.ts
+++ b/packages/backend/src/models/Meta.ts
@@ -412,6 +412,12 @@ export class MiMeta {
})
public privacyPolicyUrl: string | null;
+ @Column('varchar', {
+ length: 1024,
+ nullable: true,
+ })
+ public inquiryUrl: string | null;
+
@Column('varchar', {
length: 8192,
nullable: true,
diff --git a/packages/backend/src/models/Note.ts b/packages/backend/src/models/Note.ts
index 02df6e0ecb..9709dc840c 100644
--- a/packages/backend/src/models/Note.ts
+++ b/packages/backend/src/models/Note.ts
@@ -42,7 +42,8 @@ export class MiNote {
public replyId: MiNote['id'] | null;
@ManyToOne(type => MiNote, {
- onDelete: 'CASCADE',
+ // onDelete: 'CASCADE',
+ onDelete: 'SET NULL',
})
@JoinColumn()
public reply: MiNote | null;
diff --git a/packages/backend/src/models/Poll.ts b/packages/backend/src/models/Poll.ts
index c2693dbb19..89e576489c 100644
--- a/packages/backend/src/models/Poll.ts
+++ b/packages/backend/src/models/Poll.ts
@@ -5,6 +5,7 @@
import { PrimaryColumn, Entity, Index, JoinColumn, Column, OneToOne } from 'typeorm';
import { noteVisibilities } from '@/types.js';
+import type { MiChannel } from '@/models/Channel.js';
import { id } from './util/id.js';
import { MiNote } from './Note.js';
import type { MiUser } from './User.js';
@@ -58,6 +59,14 @@ export class MiPoll {
comment: '[Denormalized]',
})
public userHost: string | null;
+
+ @Index()
+ @Column({
+ ...id(),
+ nullable: true,
+ comment: '[Denormalized]',
+ })
+ public channelId: MiChannel['id'] | null;
//#endregion
constructor(data: Partial) {
diff --git a/packages/backend/src/models/RepositoryModule.ts b/packages/backend/src/models/RepositoryModule.ts
index 5cbd71bf27..325645cbd6 100644
--- a/packages/backend/src/models/RepositoryModule.ts
+++ b/packages/backend/src/models/RepositoryModule.ts
@@ -5,451 +5,540 @@
import { Module } from '@nestjs/common';
import { DI } from '@/di-symbols.js';
-import { MiAbuseReportResolver, MiAbuseUserReport, MiAccessToken, MiAd, MiAnnouncement, MiAnnouncementRead, MiAntenna, MiApp, MiAuthSession, MiAvatarDecoration, MiBlocking, MiChannel, MiChannelFavorite, MiChannelFollowing, MiClip, MiClipFavorite, MiClipNote, MiDriveFile, MiDriveFolder, MiEmoji, MiEvent, MiFlash, MiFlashLike, MiFollowRequest, MiFollowing, MiGalleryLike, MiGalleryPost, MiHashtag, MiInstance, MiMessagingMessage, MiMeta, MiModerationLog, MiMuting, MiNote, MiNoteFavorite, MiNoteReaction, MiNoteThreadMuting, MiNoteUnread, MiPage, MiPageLike, MiPasswordResetRequest, MiPoll, MiPollVote, MiPromoNote, MiPromoRead, MiRegistrationTicket, MiRegistryItem, MiRelay, MiRenoteMuting, MiRetentionAggregation, MiRole, MiRoleAssignment, MiSignin, MiSwSubscription, MiUsedUsername, MiUser, MiUserGroup, MiUserGroupJoining, MiUserGroupInvitation, MiUserIp, MiUserKeypair, MiUserList, MiUserListFavorite, MiUserListMembership, MiUserMemo, MiUserNotePining, MiUserPending, MiUserProfile, MiUserPublickey, MiUserSecurityKey, MiWebhook, MiBubbleGameRecord, MiReversiGame } from './_.js';
-import type { DataSource } from 'typeorm';
+import {
+ MiAbuseReportNotificationRecipient,
+ MiAbuseReportResolver,
+ MiAbuseUserReport,
+ MiAccessToken,
+ MiAd,
+ MiAnnouncement,
+ MiAnnouncementRead,
+ MiAntenna,
+ MiApp,
+ MiAuthSession,
+ MiAvatarDecoration,
+ MiBlocking,
+ MiBubbleGameRecord,
+ MiChannel,
+ MiChannelFavorite,
+ MiChannelFollowing,
+ MiClip,
+ MiClipFavorite,
+ MiClipNote,
+ MiDriveFile,
+ MiDriveFolder,
+ MiEmoji,
+ MiEvent,
+ MiFlash,
+ MiFlashLike,
+ MiFollowing,
+ MiFollowRequest,
+ MiGalleryLike,
+ MiGalleryPost,
+ MiHashtag,
+ MiInstance,
+ MiMessagingMessage,
+ MiMeta,
+ MiModerationLog,
+ MiMuting,
+ MiNote,
+ MiNoteFavorite,
+ MiNoteReaction,
+ MiNoteThreadMuting,
+ MiNoteUnread,
+ MiPage,
+ MiPageLike,
+ MiPasswordResetRequest,
+ MiPoll,
+ MiPollVote,
+ MiPromoNote,
+ MiPromoRead,
+ MiRegistrationTicket,
+ MiRegistryItem,
+ MiRelay,
+ MiRenoteMuting,
+ MiRepository,
+ miRepository,
+ MiRetentionAggregation,
+ MiReversiGame,
+ MiRole,
+ MiRoleAssignment,
+ MiSignin,
+ MiSwSubscription,
+ MiSystemWebhook,
+ MiUsedUsername,
+ MiUser,
+ MiUserGroup,
+ MiUserGroupJoining,
+ MiUserGroupInvitation,
+ MiUserIp,
+ MiUserKeypair,
+ MiUserList,
+ MiUserListFavorite,
+ MiUserListMembership,
+ MiUserMemo,
+ MiUserNotePining,
+ MiUserPending,
+ MiUserProfile,
+ MiUserPublickey,
+ MiUserSecurityKey,
+ MiWebhook,
+} from './_.js';
import type { Provider } from '@nestjs/common';
+import type { DataSource } from 'typeorm';
const $usersRepository: Provider = {
provide: DI.usersRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUser),
+ useFactory: (db: DataSource) => db.getRepository(MiUser).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $notesRepository: Provider = {
provide: DI.notesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiNote),
+ useFactory: (db: DataSource) => db.getRepository(MiNote).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $announcementsRepository: Provider = {
provide: DI.announcementsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAnnouncement),
+ useFactory: (db: DataSource) => db.getRepository(MiAnnouncement).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $announcementReadsRepository: Provider = {
provide: DI.announcementReadsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAnnouncementRead),
+ useFactory: (db: DataSource) => db.getRepository(MiAnnouncementRead).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $appsRepository: Provider = {
provide: DI.appsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiApp),
+ useFactory: (db: DataSource) => db.getRepository(MiApp).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $avatarDecorationsRepository: Provider = {
provide: DI.avatarDecorationsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAvatarDecoration),
+ useFactory: (db: DataSource) => db.getRepository(MiAvatarDecoration).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $noteFavoritesRepository: Provider = {
provide: DI.noteFavoritesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiNoteFavorite),
+ useFactory: (db: DataSource) => db.getRepository(MiNoteFavorite).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $noteThreadMutingsRepository: Provider = {
provide: DI.noteThreadMutingsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiNoteThreadMuting),
+ useFactory: (db: DataSource) => db.getRepository(MiNoteThreadMuting).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $noteReactionsRepository: Provider = {
provide: DI.noteReactionsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiNoteReaction),
+ useFactory: (db: DataSource) => db.getRepository(MiNoteReaction).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $noteUnreadsRepository: Provider = {
provide: DI.noteUnreadsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiNoteUnread),
+ useFactory: (db: DataSource) => db.getRepository(MiNoteUnread).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $pollsRepository: Provider = {
provide: DI.pollsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiPoll),
+ useFactory: (db: DataSource) => db.getRepository(MiPoll).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $pollVotesRepository: Provider = {
provide: DI.pollVotesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiPollVote),
+ useFactory: (db: DataSource) => db.getRepository(MiPollVote).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userProfilesRepository: Provider = {
provide: DI.userProfilesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserProfile),
+ useFactory: (db: DataSource) => db.getRepository(MiUserProfile).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userKeypairsRepository: Provider = {
provide: DI.userKeypairsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserKeypair),
+ useFactory: (db: DataSource) => db.getRepository(MiUserKeypair).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userPendingsRepository: Provider = {
provide: DI.userPendingsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserPending),
+ useFactory: (db: DataSource) => db.getRepository(MiUserPending).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userSecurityKeysRepository: Provider = {
provide: DI.userSecurityKeysRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserSecurityKey),
+ useFactory: (db: DataSource) => db.getRepository(MiUserSecurityKey).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userPublickeysRepository: Provider = {
provide: DI.userPublickeysRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserPublickey),
+ useFactory: (db: DataSource) => db.getRepository(MiUserPublickey).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userListsRepository: Provider = {
provide: DI.userListsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserList),
+ useFactory: (db: DataSource) => db.getRepository(MiUserList).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userListFavoritesRepository: Provider = {
provide: DI.userListFavoritesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserListFavorite),
+ useFactory: (db: DataSource) => db.getRepository(MiUserListFavorite).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userListMembershipsRepository: Provider = {
provide: DI.userListMembershipsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserListMembership),
+ useFactory: (db: DataSource) => db.getRepository(MiUserListMembership).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userGroupsRepository: Provider = {
provide: DI.userGroupsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserGroup),
+ useFactory: (db: DataSource) => db.getRepository(MiUserGroup).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userGroupJoiningsRepository: Provider = {
provide: DI.userGroupJoiningsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserGroupJoining),
+ useFactory: (db: DataSource) => db.getRepository(MiUserGroupJoining).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userGroupInvitationsRepository: Provider = {
provide: DI.userGroupInvitationsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserGroupInvitation),
+ useFactory: (db: DataSource) => db.getRepository(MiUserGroupInvitation).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userNotePiningsRepository: Provider = {
provide: DI.userNotePiningsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserNotePining),
+ useFactory: (db: DataSource) => db.getRepository(MiUserNotePining).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userIpsRepository: Provider = {
provide: DI.userIpsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserIp),
+ useFactory: (db: DataSource) => db.getRepository(MiUserIp).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $usedUsernamesRepository: Provider = {
provide: DI.usedUsernamesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUsedUsername),
+ useFactory: (db: DataSource) => db.getRepository(MiUsedUsername).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $followingsRepository: Provider = {
provide: DI.followingsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiFollowing),
+ useFactory: (db: DataSource) => db.getRepository(MiFollowing).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $followRequestsRepository: Provider = {
provide: DI.followRequestsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiFollowRequest),
+ useFactory: (db: DataSource) => db.getRepository(MiFollowRequest).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $instancesRepository: Provider = {
provide: DI.instancesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiInstance),
+ useFactory: (db: DataSource) => db.getRepository(MiInstance).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $emojisRepository: Provider = {
provide: DI.emojisRepository,
- useFactory: (db: DataSource) => db.getRepository(MiEmoji),
+ useFactory: (db: DataSource) => db.getRepository(MiEmoji).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $eventsRepository: Provider = {
provide: DI.eventsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiEvent),
+ useFactory: (db: DataSource) => db.getRepository(MiEvent).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $driveFilesRepository: Provider = {
provide: DI.driveFilesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiDriveFile),
+ useFactory: (db: DataSource) => db.getRepository(MiDriveFile).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $driveFoldersRepository: Provider = {
provide: DI.driveFoldersRepository,
- useFactory: (db: DataSource) => db.getRepository(MiDriveFolder),
+ useFactory: (db: DataSource) => db.getRepository(MiDriveFolder).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $metasRepository: Provider = {
provide: DI.metasRepository,
- useFactory: (db: DataSource) => db.getRepository(MiMeta),
+ useFactory: (db: DataSource) => db.getRepository(MiMeta).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $mutingsRepository: Provider = {
provide: DI.mutingsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiMuting),
+ useFactory: (db: DataSource) => db.getRepository(MiMuting).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $renoteMutingsRepository: Provider = {
provide: DI.renoteMutingsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiRenoteMuting),
+ useFactory: (db: DataSource) => db.getRepository(MiRenoteMuting).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $blockingsRepository: Provider = {
provide: DI.blockingsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiBlocking),
+ useFactory: (db: DataSource) => db.getRepository(MiBlocking).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $swSubscriptionsRepository: Provider = {
provide: DI.swSubscriptionsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiSwSubscription),
+ useFactory: (db: DataSource) => db.getRepository(MiSwSubscription).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $hashtagsRepository: Provider = {
provide: DI.hashtagsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiHashtag),
+ useFactory: (db: DataSource) => db.getRepository(MiHashtag).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $abuseUserReportsRepository: Provider = {
provide: DI.abuseUserReportsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAbuseUserReport),
+ useFactory: (db: DataSource) => db.getRepository(MiAbuseUserReport).extend(miRepository as MiRepository),
+ inject: [DI.db],
+};
+
+const $abuseReportNotificationRecipientRepository: Provider = {
+ provide: DI.abuseReportNotificationRecipientRepository,
+ useFactory: (db: DataSource) => db.getRepository(MiAbuseReportNotificationRecipient),
inject: [DI.db],
};
const $registrationTicketsRepository: Provider = {
provide: DI.registrationTicketsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiRegistrationTicket),
+ useFactory: (db: DataSource) => db.getRepository(MiRegistrationTicket).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $authSessionsRepository: Provider = {
provide: DI.authSessionsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAuthSession),
+ useFactory: (db: DataSource) => db.getRepository(MiAuthSession).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $accessTokensRepository: Provider = {
provide: DI.accessTokensRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAccessToken),
+ useFactory: (db: DataSource) => db.getRepository(MiAccessToken).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $signinsRepository: Provider = {
provide: DI.signinsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiSignin),
+ useFactory: (db: DataSource) => db.getRepository(MiSignin).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $messagingMessagesRepository: Provider = {
provide: DI.messagingMessagesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiMessagingMessage),
+ useFactory: (db: DataSource) => db.getRepository(MiMessagingMessage).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $pagesRepository: Provider = {
provide: DI.pagesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiPage),
+ useFactory: (db: DataSource) => db.getRepository(MiPage).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $pageLikesRepository: Provider = {
provide: DI.pageLikesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiPageLike),
+ useFactory: (db: DataSource) => db.getRepository(MiPageLike).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $galleryPostsRepository: Provider = {
provide: DI.galleryPostsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiGalleryPost),
+ useFactory: (db: DataSource) => db.getRepository(MiGalleryPost).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $galleryLikesRepository: Provider = {
provide: DI.galleryLikesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiGalleryLike),
+ useFactory: (db: DataSource) => db.getRepository(MiGalleryLike).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $moderationLogsRepository: Provider = {
provide: DI.moderationLogsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiModerationLog),
+ useFactory: (db: DataSource) => db.getRepository(MiModerationLog).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $clipsRepository: Provider = {
provide: DI.clipsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiClip),
+ useFactory: (db: DataSource) => db.getRepository(MiClip).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $clipNotesRepository: Provider = {
provide: DI.clipNotesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiClipNote),
+ useFactory: (db: DataSource) => db.getRepository(MiClipNote).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $clipFavoritesRepository: Provider = {
provide: DI.clipFavoritesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiClipFavorite),
+ useFactory: (db: DataSource) => db.getRepository(MiClipFavorite).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $antennasRepository: Provider = {
provide: DI.antennasRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAntenna),
+ useFactory: (db: DataSource) => db.getRepository(MiAntenna).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $promoNotesRepository: Provider = {
provide: DI.promoNotesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiPromoNote),
+ useFactory: (db: DataSource) => db.getRepository(MiPromoNote).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $promoReadsRepository: Provider = {
provide: DI.promoReadsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiPromoRead),
+ useFactory: (db: DataSource) => db.getRepository(MiPromoRead).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $relaysRepository: Provider = {
provide: DI.relaysRepository,
- useFactory: (db: DataSource) => db.getRepository(MiRelay),
+ useFactory: (db: DataSource) => db.getRepository(MiRelay).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $channelsRepository: Provider = {
provide: DI.channelsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiChannel),
+ useFactory: (db: DataSource) => db.getRepository(MiChannel).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $channelFollowingsRepository: Provider = {
provide: DI.channelFollowingsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiChannelFollowing),
+ useFactory: (db: DataSource) => db.getRepository(MiChannelFollowing).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $channelFavoritesRepository: Provider = {
provide: DI.channelFavoritesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiChannelFavorite),
+ useFactory: (db: DataSource) => db.getRepository(MiChannelFavorite).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $registryItemsRepository: Provider = {
provide: DI.registryItemsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiRegistryItem),
+ useFactory: (db: DataSource) => db.getRepository(MiRegistryItem).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $webhooksRepository: Provider = {
provide: DI.webhooksRepository,
- useFactory: (db: DataSource) => db.getRepository(MiWebhook),
+ useFactory: (db: DataSource) => db.getRepository(MiWebhook).extend(miRepository as MiRepository),
+ inject: [DI.db],
+};
+
+const $systemWebhooksRepository: Provider = {
+ provide: DI.systemWebhooksRepository,
+ useFactory: (db: DataSource) => db.getRepository(MiSystemWebhook),
inject: [DI.db],
};
const $adsRepository: Provider = {
provide: DI.adsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAd),
+ useFactory: (db: DataSource) => db.getRepository(MiAd).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $passwordResetRequestsRepository: Provider = {
provide: DI.passwordResetRequestsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiPasswordResetRequest),
+ useFactory: (db: DataSource) => db.getRepository(MiPasswordResetRequest).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $retentionAggregationsRepository: Provider = {
provide: DI.retentionAggregationsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiRetentionAggregation),
+ useFactory: (db: DataSource) => db.getRepository(MiRetentionAggregation).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $flashsRepository: Provider = {
provide: DI.flashsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiFlash),
+ useFactory: (db: DataSource) => db.getRepository(MiFlash).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $flashLikesRepository: Provider = {
provide: DI.flashLikesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiFlashLike),
+ useFactory: (db: DataSource) => db.getRepository(MiFlashLike).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $rolesRepository: Provider = {
provide: DI.rolesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiRole),
+ useFactory: (db: DataSource) => db.getRepository(MiRole).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $roleAssignmentsRepository: Provider = {
provide: DI.roleAssignmentsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiRoleAssignment),
+ useFactory: (db: DataSource) => db.getRepository(MiRoleAssignment).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $userMemosRepository: Provider = {
provide: DI.userMemosRepository,
- useFactory: (db: DataSource) => db.getRepository(MiUserMemo),
+ useFactory: (db: DataSource) => db.getRepository(MiUserMemo).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $bubbleGameRecordsRepository: Provider = {
provide: DI.bubbleGameRecordsRepository,
- useFactory: (db: DataSource) => db.getRepository(MiBubbleGameRecord),
+ useFactory: (db: DataSource) => db.getRepository(MiBubbleGameRecord).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $reversiGamesRepository: Provider = {
provide: DI.reversiGamesRepository,
- useFactory: (db: DataSource) => db.getRepository(MiReversiGame),
+ useFactory: (db: DataSource) => db.getRepository(MiReversiGame).extend(miRepository as MiRepository),
inject: [DI.db],
};
const $abuseReportResolversRepository: Provider = {
provide: DI.abuseReportResolversRepository,
- useFactory: (db: DataSource) => db.getRepository(MiAbuseReportResolver),
+ useFactory: (db: DataSource) => db.getRepository(MiAbuseReportResolver).extend(miRepository as MiRepository),
inject: [DI.db],
};
@Module({
- imports: [
- ],
+ imports: [],
providers: [
$usersRepository,
$notesRepository,
@@ -491,6 +580,7 @@ const $abuseReportResolversRepository: Provider = {
$swSubscriptionsRepository,
$hashtagsRepository,
$abuseUserReportsRepository,
+ $abuseReportNotificationRecipientRepository,
$registrationTicketsRepository,
$authSessionsRepository,
$accessTokensRepository,
@@ -513,6 +603,7 @@ const $abuseReportResolversRepository: Provider = {
$channelFavoritesRepository,
$registryItemsRepository,
$webhooksRepository,
+ $systemWebhooksRepository,
$adsRepository,
$passwordResetRequestsRepository,
$retentionAggregationsRepository,
@@ -566,6 +657,7 @@ const $abuseReportResolversRepository: Provider = {
$swSubscriptionsRepository,
$hashtagsRepository,
$abuseUserReportsRepository,
+ $abuseReportNotificationRecipientRepository,
$registrationTicketsRepository,
$authSessionsRepository,
$accessTokensRepository,
@@ -588,6 +680,7 @@ const $abuseReportResolversRepository: Provider = {
$channelFavoritesRepository,
$registryItemsRepository,
$webhooksRepository,
+ $systemWebhooksRepository,
$adsRepository,
$passwordResetRequestsRepository,
$retentionAggregationsRepository,
@@ -601,4 +694,5 @@ const $abuseReportResolversRepository: Provider = {
$reversiGamesRepository,
],
})
-export class RepositoryModule {}
+export class RepositoryModule {
+}
diff --git a/packages/backend/src/models/Role.ts b/packages/backend/src/models/Role.ts
index 058abe3118..a173971b2c 100644
--- a/packages/backend/src/models/Role.ts
+++ b/packages/backend/src/models/Role.ts
@@ -6,69 +6,149 @@
import { Entity, Column, PrimaryColumn } from 'typeorm';
import { id } from './util/id.js';
+/**
+ * ~かつ~
+ * 複数の条件を同時に満たす場合のみ成立とする
+ */
type CondFormulaValueAnd = {
type: 'and';
values: RoleCondFormulaValue[];
};
+/**
+ * ~または~
+ * 複数の条件のうち、いずれかを満たす場合のみ成立とする
+ */
type CondFormulaValueOr = {
type: 'or';
values: RoleCondFormulaValue[];
};
+/**
+ * ~ではない
+ * 条件を満たさない場合のみ成立とする
+ */
type CondFormulaValueNot = {
type: 'not';
value: RoleCondFormulaValue;
};
+/**
+ * ローカルユーザーのみ成立とする
+ */
type CondFormulaValueIsLocal = {
type: 'isLocal';
};
+/**
+ * リモートユーザーのみ成立とする
+ */
type CondFormulaValueIsRemote = {
type: 'isRemote';
};
+/**
+ * 既に指定のマニュアルロールにアサインされている場合のみ成立とする
+ */
type CondFormulaValueRoleAssignedTo = {
type: 'roleAssignedTo';
roleId: string;
};
+/**
+ * サスペンド済みアカウントの場合のみ成立とする
+ */
+type CondFormulaValueIsSuspended = {
+ type: 'isSuspended';
+};
+
+/**
+ * 鍵アカウントの場合のみ成立とする
+ */
+type CondFormulaValueIsLocked = {
+ type: 'isLocked';
+};
+
+/**
+ * botアカウントの場合のみ成立とする
+ */
+type CondFormulaValueIsBot = {
+ type: 'isBot';
+};
+
+/**
+ * 猫アカウントの場合のみ成立とする
+ */
+type CondFormulaValueIsCat = {
+ type: 'isCat';
+};
+
+/**
+ * 「ユーザを見つけやすくする」が有効なアカウントの場合のみ成立とする
+ */
+type CondFormulaValueIsExplorable = {
+ type: 'isExplorable';
+};
+
+/**
+ * ユーザが作成されてから指定期間経過した場合のみ成立とする
+ */
type CondFormulaValueCreatedLessThan = {
type: 'createdLessThan';
sec: number;
};
+/**
+ * ユーザが作成されてから指定期間経っていない場合のみ成立とする
+ */
type CondFormulaValueCreatedMoreThan = {
type: 'createdMoreThan';
sec: number;
};
+/**
+ * フォロワー数が指定値以下の場合のみ成立とする
+ */
type CondFormulaValueFollowersLessThanOrEq = {
type: 'followersLessThanOrEq';
value: number;
};
+/**
+ * フォロワー数が指定値以上の場合のみ成立とする
+ */
type CondFormulaValueFollowersMoreThanOrEq = {
type: 'followersMoreThanOrEq';
value: number;
};
+/**
+ * フォロー数が指定値以下の場合のみ成立とする
+ */
type CondFormulaValueFollowingLessThanOrEq = {
type: 'followingLessThanOrEq';
value: number;
};
+/**
+ * フォロー数が指定値以上の場合のみ成立とする
+ */
type CondFormulaValueFollowingMoreThanOrEq = {
type: 'followingMoreThanOrEq';
value: number;
};
+/**
+ * 投稿数が指定値以下の場合のみ成立とする
+ */
type CondFormulaValueNotesLessThanOrEq = {
type: 'notesLessThanOrEq';
value: number;
};
+/**
+ * 投稿数が指定値以上の場合のみ成立とする
+ */
type CondFormulaValueNotesMoreThanOrEq = {
type: 'notesMoreThanOrEq';
value: number;
@@ -80,6 +160,11 @@ export type RoleCondFormulaValue = { id: string } & (
CondFormulaValueNot |
CondFormulaValueIsLocal |
CondFormulaValueIsRemote |
+ CondFormulaValueIsSuspended |
+ CondFormulaValueIsLocked |
+ CondFormulaValueIsBot |
+ CondFormulaValueIsCat |
+ CondFormulaValueIsExplorable |
CondFormulaValueRoleAssignedTo |
CondFormulaValueCreatedLessThan |
CondFormulaValueCreatedMoreThan |
diff --git a/packages/backend/src/models/SystemWebhook.ts b/packages/backend/src/models/SystemWebhook.ts
new file mode 100644
index 0000000000..86fb323d1d
--- /dev/null
+++ b/packages/backend/src/models/SystemWebhook.ts
@@ -0,0 +1,98 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+import { Column, Entity, Index, PrimaryColumn } from 'typeorm';
+import { Serialized } from '@/types.js';
+import { id } from './util/id.js';
+
+export const systemWebhookEventTypes = [
+ // ユーザからの通報を受けたとき
+ 'abuseReport',
+ // 通報を処理したとき
+ 'abuseReportResolved',
+] as const;
+export type SystemWebhookEventType = typeof systemWebhookEventTypes[number];
+
+@Entity('system_webhook')
+export class MiSystemWebhook {
+ @PrimaryColumn(id())
+ public id: string;
+
+ /**
+ * 有効かどうか.
+ */
+ @Index('IDX_system_webhook_isActive', { synchronize: false })
+ @Column('boolean', {
+ default: true,
+ })
+ public isActive: boolean;
+
+ /**
+ * 更新日時.
+ */
+ @Column('timestamp with time zone', {
+ default: () => 'CURRENT_TIMESTAMP',
+ })
+ public updatedAt: Date;
+
+ /**
+ * 最後に送信された日時.
+ */
+ @Column('timestamp with time zone', {
+ nullable: true,
+ })
+ public latestSentAt: Date | null;
+
+ /**
+ * 最後に送信されたステータスコード
+ */
+ @Column('integer', {
+ nullable: true,
+ })
+ public latestStatus: number | null;
+
+ /**
+ * 通知設定名.
+ */
+ @Column('varchar', {
+ length: 255,
+ })
+ public name: string;
+
+ /**
+ * イベント種別.
+ */
+ @Index('IDX_system_webhook_on', { synchronize: false })
+ @Column('varchar', {
+ length: 128,
+ array: true,
+ default: '{}',
+ })
+ public on: SystemWebhookEventType[];
+
+ /**
+ * Webhook送信先のURL.
+ */
+ @Column('varchar', {
+ length: 1024,
+ })
+ public url: string;
+
+ /**
+ * Webhook検証用の値.
+ */
+ @Column('varchar', {
+ length: 1024,
+ })
+ public secret: string;
+
+ static deserialize(obj: Serialized): MiSystemWebhook {
+ return {
+ ...obj,
+ updatedAt: new Date(obj.updatedAt),
+ latestSentAt: obj.latestSentAt ? new Date(obj.latestSentAt) : null,
+ };
+ }
+}
diff --git a/packages/backend/src/models/_.ts b/packages/backend/src/models/_.ts
index bbbe31bd9c..ed4694f910 100644
--- a/packages/backend/src/models/_.ts
+++ b/packages/backend/src/models/_.ts
@@ -3,8 +3,16 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
+import { FindOneOptions, InsertQueryBuilder, ObjectLiteral, Repository, SelectQueryBuilder, TypeORMError } from 'typeorm';
+import { DriverUtils } from 'typeorm/driver/DriverUtils.js';
+import { RelationCountLoader } from 'typeorm/query-builder/relation-count/RelationCountLoader.js';
+import { RelationIdLoader } from 'typeorm/query-builder/relation-id/RelationIdLoader.js';
+import { RawSqlResultsToEntityTransformer } from 'typeorm/query-builder/transformer/RawSqlResultsToEntityTransformer.js';
+import { ObjectUtils } from 'typeorm/util/ObjectUtils.js';
+import { OrmUtils } from 'typeorm/util/OrmUtils.js';
import { MiAbuseReportResolver } from '@/models/AbuseReportResolver.js';
import { MiAbuseUserReport } from '@/models/AbuseUserReport.js';
+import { MiAbuseReportNotificationRecipient } from '@/models/AbuseReportNotificationRecipient.js';
import { MiAccessToken } from '@/models/AccessToken.js';
import { MiAd } from '@/models/Ad.js';
import { MiAnnouncement } from '@/models/Announcement.js';
@@ -67,6 +75,7 @@ import { MiUserPublickey } from '@/models/UserPublickey.js';
import { MiUserSecurityKey } from '@/models/UserSecurityKey.js';
import { MiUserMemo } from '@/models/UserMemo.js';
import { MiWebhook } from '@/models/Webhook.js';
+import { MiSystemWebhook } from '@/models/SystemWebhook.js';
import { MiChannel } from '@/models/Channel.js';
import { MiRetentionAggregation } from '@/models/RetentionAggregation.js';
import { MiRole } from '@/models/Role.js';
@@ -76,12 +85,75 @@ import { MiFlashLike } from '@/models/FlashLike.js';
import { MiUserListFavorite } from '@/models/UserListFavorite.js';
import { MiBubbleGameRecord } from '@/models/BubbleGameRecord.js';
import { MiReversiGame } from '@/models/ReversiGame.js';
+import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js';
-import type { Repository } from 'typeorm';
+export interface MiRepository {
+ createTableColumnNames(this: Repository & MiRepository