diff --git a/packages/backend/migration/1697420555911-deleteCreatedAt.js b/packages/backend/migration/1697420555911-deleteCreatedAt.js deleted file mode 100644 index 958d61a34..000000000 --- a/packages/backend/migration/1697420555911-deleteCreatedAt.js +++ /dev/null @@ -1,144 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and other misskey contributors - * SPDX-License-Identifier: AGPL-3.0-only - */ - -export class DeleteCreatedAt1697420555911 { - name = 'DeleteCreatedAt1697420555911' - - async up(queryRunner) { - await queryRunner.query(`DROP INDEX "public"."IDX_02878d441ceae15ce060b73daf"`); - await queryRunner.query(`DROP INDEX "public"."IDX_c8dfad3b72196dd1d6b5db168a"`); - await queryRunner.query(`DROP INDEX "public"."IDX_e11e649824a45d8ed01d597fd9"`); - await queryRunner.query(`DROP INDEX "public"."IDX_db2098070b2b5a523c58181f74"`); - await queryRunner.query(`DROP INDEX "public"."IDX_048a757923ed8b157e9895da53"`); - await queryRunner.query(`DROP INDEX "public"."IDX_1129c2ef687fc272df040bafaa"`); - await queryRunner.query(`DROP INDEX "public"."IDX_118ec703e596086fc4515acb39"`); - await queryRunner.query(`DROP INDEX "public"."IDX_b9a354f7941c1e779f3b33aea6"`); - await queryRunner.query(`DROP INDEX "public"."IDX_71cb7b435b7c0d4843317e7e16"`); - await queryRunner.query(`DROP INDEX "public"."IDX_11e71f2511589dcc8a4d3214f9"`); - await queryRunner.query(`DROP INDEX "public"."IDX_735a5544f9249d412255f47f95"`); - await queryRunner.query(`DROP INDEX "public"."IDX_582f8fab771a9040a12961f3e7"`); - await queryRunner.query(`DROP INDEX "public"."IDX_8f1a239bd077c8864a20c62c2c"`); - await queryRunner.query(`DROP INDEX "public"."IDX_f86d57fbca33c7a4e6897490cc"`); - await queryRunner.query(`DROP INDEX "public"."IDX_d1259a2c2b7bb413ff449e8711"`); - await queryRunner.query(`DROP INDEX "public"."IDX_fbb4297c927a9b85e9cefa2eb1"`); - await queryRunner.query(`DROP INDEX "public"."IDX_0fb627e1c2f753262a74f0562d"`); - await queryRunner.query(`DROP INDEX "public"."IDX_149d2e44785707548c82999b01"`); - await queryRunner.query(`ALTER TABLE "drive_folder" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "drive_file" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "app" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "access_token" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "ad" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "announcement" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "announcement_read" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "user_list" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "auth_session" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "blocking" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "channel" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "channel_following" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "channel_favorite" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "clip" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "note" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "clip_favorite" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "following" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "follow_request" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "gallery_post" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "gallery_like" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "moderation_log" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "muting" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "renote_muting" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "note_favorite" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "note_reaction" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "note_thread_muting" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "page" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "page_like" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "password_reset_request" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "poll_vote" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "promo_read" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "registration_ticket" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "registry_item" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "signin" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "sw_subscription" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "user_list_favorite" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "user_list_membership" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "user_note_pining" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "user_pending" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "webhook" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "role" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "role_assignment" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "flash" DROP COLUMN "createdAt"`); - await queryRunner.query(`ALTER TABLE "flash_like" DROP COLUMN "createdAt"`); - } - - async down(queryRunner) { - await queryRunner.query(`ALTER TABLE "flash_like" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "flash" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "role_assignment" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "role" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "webhook" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "user_pending" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "user_note_pining" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "user_list_membership" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "user_list_favorite" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "sw_subscription" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "signin" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "registry_item" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "registration_ticket" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "promo_read" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "poll_vote" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "password_reset_request" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "page_like" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "page" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "note_thread_muting" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "note_reaction" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "note_favorite" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "renote_muting" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "muting" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "moderation_log" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "gallery_like" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "gallery_post" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "follow_request" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "following" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "clip_favorite" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "note" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "clip" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "channel_favorite" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "channel_following" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "channel" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "blocking" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "auth_session" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "antenna" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "user_list" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "announcement_read" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "announcement" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "ad" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "access_token" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "app" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "user" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "drive_file" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`ALTER TABLE "drive_folder" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL`); - await queryRunner.query(`CREATE INDEX "IDX_149d2e44785707548c82999b01" ON "flash" ("createdAt") `); - await queryRunner.query(`CREATE INDEX "IDX_0fb627e1c2f753262a74f0562d" ON "poll_vote" ("createdAt") `); - await queryRunner.query(`CREATE INDEX "IDX_fbb4297c927a9b85e9cefa2eb1" ON "page" ("createdAt") `); - await queryRunner.query(`CREATE INDEX "IDX_d1259a2c2b7bb413ff449e8711" ON "renote_muting" ("createdAt") `); - await queryRunner.query(`CREATE INDEX "IDX_f86d57fbca33c7a4e6897490cc" ON "muting" ("createdAt") `); - await queryRunner.query(`CREATE INDEX "IDX_8f1a239bd077c8864a20c62c2c" ON "gallery_post" ("createdAt") `); - await queryRunner.query(`CREATE INDEX "IDX_582f8fab771a9040a12961f3e7" ON "following" ("createdAt") `); - await queryRunner.query(`CREATE INDEX "IDX_735a5544f9249d412255f47f95" ON "channel_favorite" ("createdAt") `); - await queryRunner.query(`CREATE INDEX "IDX_11e71f2511589dcc8a4d3214f9" ON "channel_following" ("createdAt") `); - await queryRunner.query(`CREATE INDEX "IDX_71cb7b435b7c0d4843317e7e16" ON "channel" ("createdAt") `); - await queryRunner.query(`CREATE INDEX "IDX_b9a354f7941c1e779f3b33aea6" ON "blocking" ("createdAt") `); - await queryRunner.query(`CREATE INDEX "IDX_118ec703e596086fc4515acb39" ON "announcement" ("createdAt") `); - await queryRunner.query(`CREATE INDEX "IDX_1129c2ef687fc272df040bafaa" ON "ad" ("createdAt") `); - await queryRunner.query(`CREATE INDEX "IDX_048a757923ed8b157e9895da53" ON "app" ("createdAt") `); - await queryRunner.query(`CREATE INDEX "IDX_db2098070b2b5a523c58181f74" ON "abuse_user_report" ("createdAt") `); - await queryRunner.query(`CREATE INDEX "IDX_e11e649824a45d8ed01d597fd9" ON "user" ("createdAt") `); - await queryRunner.query(`CREATE INDEX "IDX_c8dfad3b72196dd1d6b5db168a" ON "drive_file" ("createdAt") `); - await queryRunner.query(`CREATE INDEX "IDX_02878d441ceae15ce060b73daf" ON "drive_folder" ("createdAt") `); - } -} diff --git a/packages/backend/migration/1700415938358-createdAt-default.js b/packages/backend/migration/1700415938358-createdAt-default.js new file mode 100644 index 000000000..deaa7927f --- /dev/null +++ b/packages/backend/migration/1700415938358-createdAt-default.js @@ -0,0 +1,224 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class CreatedAtDefault1700415938358 { + name = 'CreatedAtDefault1700415938358' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "avatar_decoration" ADD "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()`); + await queryRunner.query(`COMMENT ON COLUMN "avatar_decoration"."createdAt" IS 'The created date of the AvatarDecoration.'`); + await queryRunner.query(`COMMENT ON COLUMN "abuse_report_resolver"."createdAt" IS 'The created date of the AbuseReportResolver.'`); + await queryRunner.query(`ALTER TABLE "abuse_report_resolver" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "drive_folder" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "user" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "abuse_user_report" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "app" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "access_token" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "ad" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "announcement" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "announcement_read" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "user_list" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "antenna" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "auth_session" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "blocking" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "channel" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "channel_following" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "channel_favorite" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "clip" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "note" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`COMMENT ON COLUMN "clip_favorite"."createdAt" IS 'The created date of the ClipFavorite.'`); + await queryRunner.query(`ALTER TABLE "clip_favorite" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "following" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "follow_request" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "gallery_post" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`COMMENT ON COLUMN "gallery_like"."createdAt" IS 'The created date of the GalleryLike.'`); + await queryRunner.query(`ALTER TABLE "gallery_like" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "preservedUsernames" SET DEFAULT '{ "admin", "administrator", "root", "system", "maintainer", "host", "mod", "moderator", "owner", "superuser", "staff", "auth", "i", "me", "everyone", "all", "mention", "mentions", "example", "user", "users", "account", "accounts", "official", "help", "helps", "support", "supports", "info", "information", "informations", "announce", "announces", "announcement", "announcements", "notice", "notification", "notifications", "dev", "developer", "developers", "tech", "misskey" }'`); + await queryRunner.query(`ALTER TABLE "moderation_log" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "muting" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`COMMENT ON COLUMN "renote_muting"."createdAt" IS 'The created date of the RenoteMuting.'`); + await queryRunner.query(`ALTER TABLE "renote_muting" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "note_favorite" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "note_reaction" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`COMMENT ON COLUMN "note_thread_muting"."createdAt" IS 'The created date of the NoteThreadMuting.'`); + await queryRunner.query(`ALTER TABLE "note_thread_muting" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "page" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`COMMENT ON COLUMN "page_like"."createdAt" IS 'The created date of the PageLike.'`); + await queryRunner.query(`ALTER TABLE "page_like" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`COMMENT ON COLUMN "password_reset_request"."createdAt" IS 'The created date of the PasswordResetRequest.'`); + await queryRunner.query(`ALTER TABLE "password_reset_request" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "poll_vote" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "promo_read" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`COMMENT ON COLUMN "registration_ticket"."createdAt" IS 'The created date of the RegistrationTicket.'`); + await queryRunner.query(`ALTER TABLE "registration_ticket" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "registry_item" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "signin" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`COMMENT ON COLUMN "sw_subscription"."createdAt" IS 'The created date of the SwSubscriptipnpon.'`); + await queryRunner.query(`ALTER TABLE "sw_subscription" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`COMMENT ON COLUMN "used_username"."createdAt" IS 'The created date of the UsedUsername.'`); + await queryRunner.query(`ALTER TABLE "used_username" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`COMMENT ON COLUMN "user_ip"."createdAt" IS 'The created date of the UserIp.'`); + await queryRunner.query(`ALTER TABLE "user_ip" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`COMMENT ON COLUMN "user_list_favorite"."createdAt" IS 'The created date of the UserListFavorite.'`); + await queryRunner.query(`ALTER TABLE "user_list_favorite" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "user_list_membership" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`COMMENT ON COLUMN "user_note_pining"."createdAt" IS 'The created date of the UserNotePining.'`); + await queryRunner.query(`ALTER TABLE "user_note_pining" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`COMMENT ON COLUMN "user_pending"."createdAt" IS 'The created date of the UserPending.'`); + await queryRunner.query(`ALTER TABLE "user_pending" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`COMMENT ON COLUMN "webhook"."createdAt" IS 'The created date of the Webhook.'`); + await queryRunner.query(`ALTER TABLE "webhook" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`COMMENT ON COLUMN "retention_aggregation"."createdAt" IS 'The created date of the GalleryPost.'`); + await queryRunner.query(`ALTER TABLE "retention_aggregation" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "role" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "role_assignment" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "flash" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`ALTER TABLE "flash" ALTER COLUMN "visibility" SET NOT NULL`); + await queryRunner.query(`COMMENT ON COLUMN "flash_like"."createdAt" IS 'The created date of the FlashLike.'`); + await queryRunner.query(`ALTER TABLE "flash_like" ALTER COLUMN "createdAt" SET DEFAULT now()`); + await queryRunner.query(`CREATE INDEX "IDX_f9b40730606162a441c7acb3e5" ON "access_token" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_cbca0122587e5a757ea0e584f0" ON "announcement_read" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_1383c050b99ba7deb995207afe" ON "user_list" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_9425d976c9cf6d47d2b9956344" ON "antenna" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_a3aca00bb7f8d79408edfefe67" ON "avatar_decoration" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_407e3e07747e5cebb916e77914" ON "auth_session" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_823073a0f1f5d44ef83917e0c4" ON "clip" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_e7c0567f5261063592f022e9b5" ON "note" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_94af6cc88a484caf0cd53bfec9" ON "clip_favorite" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_9a20428737dfc7c515fc31c9bc" ON "follow_request" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_3712d1129515e88dedc7c0ca9b" ON "gallery_like" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_1c32fad73f120e11702982f713" ON "moderation_log" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_b7a97c1435dfa03ab42ab7ec92" ON "note_favorite" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_01f4581f114e0ebd2bbb876f0b" ON "note_reaction" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_51fe96e68f335de120a5f8974b" ON "note_thread_muting" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_b72859eb6173fd2e176aad3fbc" ON "page_like" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_0123b5cc155383f3d380170774" ON "password_reset_request" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_65a0babf63cec88aaa804332a0" ON "promo_read" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_0bf1bd10114284dc984d900c8b" ON "registration_ticket" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_0ff7393a15d37079be4e1f2bd5" ON "registry_item" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_68e9b8637a5b186f242d81e41a" ON "signin" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_8781b31c9b1e5c6c0b1cf904c0" ON "sw_subscription" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_4ac8a879384f3fc210bbaa21bc" ON "used_username" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_e15e78ed889553e314336e4952" ON "user_ip" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_970ffee983708c114a0c289903" ON "user_list_favorite" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_d6d398ea7c0d187aa9a91c4ad0" ON "user_list_membership" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_61347f72791a48bfaa9244eb05" ON "user_note_pining" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_e9181436b1294069148b5ba491" ON "user_pending" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_7ad27f46c9449fe9d6fbb4c79c" ON "webhook" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_3c39bd046f5e69d37f0e4fe768" ON "role" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_fe3eb6be723a95c6b7ce539a4f" ON "role_assignment" ("createdAt") `); + await queryRunner.query(`CREATE INDEX "IDX_89523d5c47dc3fcc0bd6793f18" ON "flash_like" ("createdAt") `); + await queryRunner.query(`ALTER TABLE "announcement" ADD CONSTRAINT "FK_fd25dfe3da37df1715f11ba6ec8" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "announcement" DROP CONSTRAINT "FK_fd25dfe3da37df1715f11ba6ec8"`); + await queryRunner.query(`DROP INDEX "public"."IDX_89523d5c47dc3fcc0bd6793f18"`); + await queryRunner.query(`DROP INDEX "public"."IDX_fe3eb6be723a95c6b7ce539a4f"`); + await queryRunner.query(`DROP INDEX "public"."IDX_3c39bd046f5e69d37f0e4fe768"`); + await queryRunner.query(`DROP INDEX "public"."IDX_7ad27f46c9449fe9d6fbb4c79c"`); + await queryRunner.query(`DROP INDEX "public"."IDX_e9181436b1294069148b5ba491"`); + await queryRunner.query(`DROP INDEX "public"."IDX_61347f72791a48bfaa9244eb05"`); + await queryRunner.query(`DROP INDEX "public"."IDX_d6d398ea7c0d187aa9a91c4ad0"`); + await queryRunner.query(`DROP INDEX "public"."IDX_970ffee983708c114a0c289903"`); + await queryRunner.query(`DROP INDEX "public"."IDX_e15e78ed889553e314336e4952"`); + await queryRunner.query(`DROP INDEX "public"."IDX_4ac8a879384f3fc210bbaa21bc"`); + await queryRunner.query(`DROP INDEX "public"."IDX_8781b31c9b1e5c6c0b1cf904c0"`); + await queryRunner.query(`DROP INDEX "public"."IDX_68e9b8637a5b186f242d81e41a"`); + await queryRunner.query(`DROP INDEX "public"."IDX_0ff7393a15d37079be4e1f2bd5"`); + await queryRunner.query(`DROP INDEX "public"."IDX_0bf1bd10114284dc984d900c8b"`); + await queryRunner.query(`DROP INDEX "public"."IDX_65a0babf63cec88aaa804332a0"`); + await queryRunner.query(`DROP INDEX "public"."IDX_0123b5cc155383f3d380170774"`); + await queryRunner.query(`DROP INDEX "public"."IDX_b72859eb6173fd2e176aad3fbc"`); + await queryRunner.query(`DROP INDEX "public"."IDX_51fe96e68f335de120a5f8974b"`); + await queryRunner.query(`DROP INDEX "public"."IDX_01f4581f114e0ebd2bbb876f0b"`); + await queryRunner.query(`DROP INDEX "public"."IDX_b7a97c1435dfa03ab42ab7ec92"`); + await queryRunner.query(`DROP INDEX "public"."IDX_1c32fad73f120e11702982f713"`); + await queryRunner.query(`DROP INDEX "public"."IDX_3712d1129515e88dedc7c0ca9b"`); + await queryRunner.query(`DROP INDEX "public"."IDX_9a20428737dfc7c515fc31c9bc"`); + await queryRunner.query(`DROP INDEX "public"."IDX_94af6cc88a484caf0cd53bfec9"`); + await queryRunner.query(`DROP INDEX "public"."IDX_e7c0567f5261063592f022e9b5"`); + await queryRunner.query(`DROP INDEX "public"."IDX_823073a0f1f5d44ef83917e0c4"`); + await queryRunner.query(`DROP INDEX "public"."IDX_407e3e07747e5cebb916e77914"`); + await queryRunner.query(`DROP INDEX "public"."IDX_a3aca00bb7f8d79408edfefe67"`); + await queryRunner.query(`DROP INDEX "public"."IDX_9425d976c9cf6d47d2b9956344"`); + await queryRunner.query(`DROP INDEX "public"."IDX_1383c050b99ba7deb995207afe"`); + await queryRunner.query(`DROP INDEX "public"."IDX_cbca0122587e5a757ea0e584f0"`); + await queryRunner.query(`DROP INDEX "public"."IDX_f9b40730606162a441c7acb3e5"`); + await queryRunner.query(`ALTER TABLE "flash_like" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`COMMENT ON COLUMN "flash_like"."createdAt" IS NULL`); + await queryRunner.query(`ALTER TABLE "flash" ALTER COLUMN "visibility" DROP NOT NULL`); + await queryRunner.query(`ALTER TABLE "flash" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "role_assignment" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "role" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "retention_aggregation" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`COMMENT ON COLUMN "retention_aggregation"."createdAt" IS 'The created date of the Note.'`); + await queryRunner.query(`ALTER TABLE "webhook" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`COMMENT ON COLUMN "webhook"."createdAt" IS 'The created date of the Antenna.'`); + await queryRunner.query(`ALTER TABLE "user_pending" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`COMMENT ON COLUMN "user_pending"."createdAt" IS NULL`); + await queryRunner.query(`ALTER TABLE "user_note_pining" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`COMMENT ON COLUMN "user_note_pining"."createdAt" IS 'The created date of the UserNotePinings.'`); + await queryRunner.query(`ALTER TABLE "user_list_membership" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "user_list_favorite" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`COMMENT ON COLUMN "user_list_favorite"."createdAt" IS NULL`); + await queryRunner.query(`ALTER TABLE "user_ip" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`COMMENT ON COLUMN "user_ip"."createdAt" IS NULL`); + await queryRunner.query(`ALTER TABLE "used_username" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`COMMENT ON COLUMN "used_username"."createdAt" IS NULL`); + await queryRunner.query(`ALTER TABLE "sw_subscription" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`COMMENT ON COLUMN "sw_subscription"."createdAt" IS NULL`); + await queryRunner.query(`ALTER TABLE "signin" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "registry_item" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "registration_ticket" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`COMMENT ON COLUMN "registration_ticket"."createdAt" IS NULL`); + await queryRunner.query(`ALTER TABLE "promo_read" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "poll_vote" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "password_reset_request" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`COMMENT ON COLUMN "password_reset_request"."createdAt" IS NULL`); + await queryRunner.query(`ALTER TABLE "page_like" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`COMMENT ON COLUMN "page_like"."createdAt" IS NULL`); + await queryRunner.query(`ALTER TABLE "page" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "note_thread_muting" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`COMMENT ON COLUMN "note_thread_muting"."createdAt" IS NULL`); + await queryRunner.query(`ALTER TABLE "note_reaction" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "note_favorite" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "renote_muting" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`COMMENT ON COLUMN "renote_muting"."createdAt" IS 'The created date of the Muting.'`); + await queryRunner.query(`ALTER TABLE "muting" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "moderation_log" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "preservedUsernames" SET DEFAULT '{admin,administrator,root,system,maintainer,host,mod,moderator,owner,superuser,staff,auth,i,me,everyone,all,mention,mentions,example,user,users,account,accounts,official,help,helps,support,supports,info,information,informations,announce,announces,announcement,announcements,notice,notification,notifications,dev,developer,developers,tech,misskey}'`); + await queryRunner.query(`ALTER TABLE "gallery_like" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`COMMENT ON COLUMN "gallery_like"."createdAt" IS NULL`); + await queryRunner.query(`ALTER TABLE "gallery_post" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "follow_request" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "following" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "clip_favorite" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`COMMENT ON COLUMN "clip_favorite"."createdAt" IS NULL`); + await queryRunner.query(`ALTER TABLE "note" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "clip" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "channel_favorite" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "channel_following" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "channel" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "blocking" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "auth_session" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "antenna" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "user_list" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "announcement_read" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "announcement" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "ad" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "access_token" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "app" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "abuse_user_report" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "user" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "drive_file" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "drive_folder" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`ALTER TABLE "abuse_report_resolver" ALTER COLUMN "createdAt" DROP DEFAULT`); + await queryRunner.query(`COMMENT ON COLUMN "abuse_report_resolver"."createdAt" IS 'The created date of AbuseReportResolver'`); + await queryRunner.query(`COMMENT ON COLUMN "avatar_decoration"."createdAt" IS 'The created date of the AvatarDecoration.'`); + await queryRunner.query(`ALTER TABLE "avatar_decoration" DROP COLUMN "createdAt"`); + } +} diff --git a/packages/backend/src/core/AnnouncementService.ts b/packages/backend/src/core/AnnouncementService.ts index c0e7111a7..58b07bef9 100644 --- a/packages/backend/src/core/AnnouncementService.ts +++ b/packages/backend/src/core/AnnouncementService.ts @@ -12,9 +12,10 @@ import { MiAnnouncementRead } from '@/models/_.js'; import { bindThis } from '@/decorators.js'; import { Packed } from '@/misc/json-schema.js'; import { IdService } from '@/core/IdService.js'; +import { UserEntityService } from '@/core/entities/UserEntityService.js'; +import { AnnouncementEntityService } from '@/core/entities/AnnouncementEntityService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; -import { UserEntityService } from '@/core/entities/UserEntityService.js'; @Injectable() export class AnnouncementService { @@ -30,6 +31,7 @@ export class AnnouncementService { private idService: IdService, private userEntityService: UserEntityService, + private announcementEntityService: AnnouncementEntityService, private globalEventService: GlobalEventService, private moderationLogService: ModerationLogService, ) { @@ -45,7 +47,7 @@ export class AnnouncementService { @bindThis public async getUnreadAnnouncements(user: MiUser): Promise[]> { const q = this.announcementsRepository.createQueryBuilder('announcement'); - q.leftJoin( + q.leftJoinAndSelect( MiAnnouncementRead, 'read', 'read."announcementId" = announcement.id AND read."userId" = :userId', @@ -53,7 +55,8 @@ export class AnnouncementService { ); q - .where('announcement.isActive = true') + .where('read.id IS NULL') + .andWhere('announcement.isActive = true') .andWhere('announcement.silence = false') .andWhere(new Brackets(qb => { qb.orWhere('announcement.userId = :userId', { userId: user.id }); @@ -62,15 +65,14 @@ export class AnnouncementService { .andWhere(new Brackets(qb => { qb.orWhere('announcement.forExistingUsers = false'); qb.orWhere('announcement.id > :userId', { userId: user.id }); - })) - .andWhere('read.id IS NULL'); + })); q.orderBy({ 'announcement."displayOrder"': 'DESC', 'announcement.id': 'DESC', }); - return this.packMany( + return this.announcementEntityService.packMany( await q.getMany(), user, ); @@ -94,7 +96,7 @@ export class AnnouncementService { userId: values.userId, }).then(x => this.announcementsRepository.findOneByOrFail(x.identifiers[0])); - const packed = (await this.packMany([announcement], null))[0]; + const packed = (await this.announcementEntityService.packMany([announcement], null))[0]; if (values.userId) { this.globalEventService.publishMainStream(values.userId, 'announcementCreated', { @@ -136,7 +138,7 @@ export class AnnouncementService { limit: number, offset: number, moderator: MiUser, - ): Promise<(MiAnnouncement & { userInfo: Packed<'UserLite'> | null, readCount: number })[]> { + ): Promise<(MiAnnouncement & { userInfo: Packed<'UserLite'> | null, reads: number })[]> { const query = this.announcementsRepository.createQueryBuilder('announcement'); if (userId) { query.andWhere('announcement."userId" = :userId', { userId: userId }); @@ -173,7 +175,7 @@ export class AnnouncementService { return announcements.map(announcement => ({ ...announcement, userInfo: packedUsers.find(u => u.id === announcement.userId) ?? null, - readCount: reads.get(announcement) ?? 0, + reads: reads.get(announcement) ?? 0, })); } @@ -188,6 +190,7 @@ export class AnnouncementService { await this.announcementsRepository.update(announcement.id, { updatedAt: new Date(), + isActive: values.isActive, title: values.title, text: values.text, /* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- 空の文字列の場合、nullを渡すようにするため */ @@ -195,11 +198,10 @@ export class AnnouncementService { display: values.display, icon: values.icon, forExistingUsers: values.forExistingUsers, - silence: values.silence, needConfirmationToRead: values.needConfirmationToRead, closeDuration: values.closeDuration, displayOrder: values.displayOrder, - isActive: values.isActive, + silence: values.silence, userId: values.userId, }); @@ -305,7 +307,7 @@ export class AnnouncementService { 'announcement.id': 'DESC', }); - return this.packMany( + return this.announcementEntityService.packMany( await query .limit(limit) .offset(offset) @@ -315,32 +317,29 @@ export class AnnouncementService { } @bindThis - public async countUnreadAnnouncements(me: MiUser): Promise { - const query = this.announcementsRepository.createQueryBuilder('announcement'); - query.leftJoinAndSelect( + public async countUnreadAnnouncements(user: MiUser): Promise { + const q = this.announcementsRepository.createQueryBuilder('announcement'); + q.leftJoinAndSelect( MiAnnouncementRead, 'read', 'read."announcementId" = announcement.id AND read."userId" = :userId', - { userId: me.id }, + { userId: user.id }, ); - query.andWhere('read.id IS NULL'); - query.andWhere('announcement."isActive" = true'); - query - .andWhere( - new Brackets((qb) => { - qb.orWhere('announcement."userId" = :userId', { userId: me.id }); - qb.orWhere('announcement."userId" IS NULL'); - }), - ) - .andWhere( - new Brackets((qb) => { - qb.orWhere('announcement."forExistingUsers" = false'); - qb.orWhere('announcement.id > :userId', { userId: me.id }); - }), - ); + q + .where('read.id IS NULL') + .andWhere('announcement.isActive = true') + .andWhere('announcement.silence = false') + .andWhere(new Brackets(qb => { + qb.orWhere('announcement.userId = :userId', { userId: user.id }); + qb.orWhere('announcement.userId IS NULL'); + })) + .andWhere(new Brackets(qb => { + qb.orWhere('announcement.forExistingUsers = false'); + qb.orWhere('announcement.id > :userId', { userId: user.id }); + })); - return query.getCount(); + return q.getCount(); } @bindThis @@ -359,27 +358,4 @@ export class AnnouncementService { this.globalEventService.publishMainStream(user.id, 'readAllAnnouncements'); } } - - @bindThis - public async packMany( - announcements: (MiAnnouncement & { isRead?: boolean | null })[], - me: { id: MiUser['id'] } | null | undefined, - ): Promise[]> { - return announcements.map(announcement => ({ - id: announcement.id, - createdAt: this.idService.parse(announcement.id).date.toISOString(), - updatedAt: announcement.updatedAt?.toISOString() ?? null, - text: announcement.text, - title: announcement.title, - imageUrl: announcement.imageUrl, - icon: announcement.icon, - display: announcement.display, - needConfirmationToRead: announcement.needConfirmationToRead, - closeDuration: announcement.closeDuration, - displayOrder: announcement.displayOrder, - silence: announcement.silence, - forYou: announcement.userId === me?.id, - isRead: announcement.isRead ?? undefined, - })); - } } diff --git a/packages/backend/src/core/AntennaService.ts b/packages/backend/src/core/AntennaService.ts index 65be27554..cd1f32cc0 100644 --- a/packages/backend/src/core/AntennaService.ts +++ b/packages/backend/src/core/AntennaService.ts @@ -57,12 +57,14 @@ export class AntennaService implements OnApplicationShutdown { case 'antennaCreated': this.antennas.push({ ...body, + createdAt: new Date(body.createdAt), lastUsedAt: new Date(body.lastUsedAt), }); break; case 'antennaUpdated': this.antennas[this.antennas.findIndex(a => a.id === body.id)] = { ...body, + createdAt: new Date(body.createdAt), lastUsedAt: new Date(body.lastUsedAt), }; break; diff --git a/packages/backend/src/core/CoreModule.ts b/packages/backend/src/core/CoreModule.ts index 9fb29e0e6..ef224abcc 100644 --- a/packages/backend/src/core/CoreModule.ts +++ b/packages/backend/src/core/CoreModule.ts @@ -80,6 +80,7 @@ import PerUserDriveChart from './chart/charts/per-user-drive.js'; import ApRequestChart from './chart/charts/ap-request.js'; import { ChartManagementService } from './chart/ChartManagementService.js'; import { AbuseUserReportEntityService } from './entities/AbuseUserReportEntityService.js'; +import { AnnouncementEntityService } from './entities/AnnouncementEntityService.js'; import { AntennaEntityService } from './entities/AntennaEntityService.js'; import { AppEntityService } from './entities/AppEntityService.js'; import { AuthSessionEntityService } from './entities/AuthSessionEntityService.js'; @@ -214,6 +215,7 @@ const $ApRequestChart: Provider = { provide: 'ApRequestChart', useExisting: ApRe const $ChartManagementService: Provider = { provide: 'ChartManagementService', useExisting: ChartManagementService }; const $AbuseUserReportEntityService: Provider = { provide: 'AbuseUserReportEntityService', useExisting: AbuseUserReportEntityService }; +const $AnnouncementEntityService: Provider = { provide: 'AnnouncementEntityService', useExisting: AnnouncementEntityService }; const $AntennaEntityService: Provider = { provide: 'AntennaEntityService', useExisting: AntennaEntityService }; const $AppEntityService: Provider = { provide: 'AppEntityService', useExisting: AppEntityService }; const $AuthSessionEntityService: Provider = { provide: 'AuthSessionEntityService', useExisting: AuthSessionEntityService }; @@ -348,6 +350,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting ApRequestChart, ChartManagementService, AbuseUserReportEntityService, + AnnouncementEntityService, AntennaEntityService, AppEntityService, AuthSessionEntityService, @@ -477,6 +480,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $ApRequestChart, $ChartManagementService, $AbuseUserReportEntityService, + $AnnouncementEntityService, $AntennaEntityService, $AppEntityService, $AuthSessionEntityService, @@ -606,6 +610,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting ApRequestChart, ChartManagementService, AbuseUserReportEntityService, + AnnouncementEntityService, AntennaEntityService, AppEntityService, AuthSessionEntityService, @@ -734,6 +739,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $ApRequestChart, $ChartManagementService, $AbuseUserReportEntityService, + $AnnouncementEntityService, $AntennaEntityService, $AppEntityService, $AuthSessionEntityService, diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 86f220abd..b6f7ee745 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -382,6 +382,7 @@ export class NoteCreateService implements OnApplicationShutdown { private async insertNote(user: { id: MiUser['id']; host: MiUser['host']; }, data: Option, tags: string[], emojis: string[], mentionedUsers: MinimumUser[]) { const insert = new MiNote({ id: this.idService.gen(data.createdAt?.getTime()), + 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, diff --git a/packages/backend/src/core/ReactionService.ts b/packages/backend/src/core/ReactionService.ts index 7ce42a3e5..d1560d2fb 100644 --- a/packages/backend/src/core/ReactionService.ts +++ b/packages/backend/src/core/ReactionService.ts @@ -158,6 +158,7 @@ export class ReactionService { const record: MiNoteReaction = { id: this.idService.gen(), + createdAt: new Date(), noteId: note.id, userId: user.id, reaction, diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index 671e23a98..5f6e8f606 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -131,6 +131,7 @@ export class RoleService implements OnApplicationShutdown { if (cached) { cached.push({ ...body, + createdAt: new Date(body.createdAt), updatedAt: new Date(body.updatedAt), lastUsedAt: new Date(body.lastUsedAt), }); @@ -144,6 +145,7 @@ export class RoleService implements OnApplicationShutdown { if (i > -1) { cached[i] = { ...body, + createdAt: new Date(body.createdAt), updatedAt: new Date(body.updatedAt), lastUsedAt: new Date(body.lastUsedAt), }; @@ -163,6 +165,7 @@ export class RoleService implements OnApplicationShutdown { if (cached) { cached.push({ ...body, + createdAt: new Date(body.createdAt), expiresAt: body.expiresAt ? new Date(body.expiresAt) : null, }); } diff --git a/packages/backend/src/core/WebhookService.ts b/packages/backend/src/core/WebhookService.ts index 930e6ef64..ff70f7bc0 100644 --- a/packages/backend/src/core/WebhookService.ts +++ b/packages/backend/src/core/WebhookService.ts @@ -51,6 +51,7 @@ export class WebhookService implements OnApplicationShutdown { if (body.active) { this.webhooks.push({ ...body, + createdAt: new Date(body.createdAt), latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null, }); } @@ -61,11 +62,13 @@ export class WebhookService implements OnApplicationShutdown { if (i > -1) { this.webhooks[i] = { ...body, + createdAt: new Date(body.createdAt), latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null, }; } else { this.webhooks.push({ ...body, + createdAt: new Date(body.createdAt), latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null, }); } diff --git a/packages/backend/src/core/entities/AnnouncementEntityService.ts b/packages/backend/src/core/entities/AnnouncementEntityService.ts new file mode 100644 index 000000000..2dc2c2cc3 --- /dev/null +++ b/packages/backend/src/core/entities/AnnouncementEntityService.ts @@ -0,0 +1,73 @@ +/* + * SPDX-FileCopyrightText: syuilo and other misskey contributors + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import { DI } from '@/di-symbols.js'; +import type { AnnouncementsRepository, AnnouncementReadsRepository, MiAnnouncement, MiUser } from "@/models/_.js"; +import type { Packed } from '@/misc/json-schema.js'; +import { bindThis } from '@/decorators.js'; +import { IdService } from '@/core/IdService.js'; + +@Injectable() +export class AnnouncementEntityService { + constructor( + @Inject(DI.announcementsRepository) + private announcementsRepository: AnnouncementsRepository, + + @Inject(DI.announcementReadsRepository) + private announcementReadsRepository: AnnouncementReadsRepository, + + private idService: IdService, + ) { + } + + @bindThis + public async pack( + src: MiAnnouncement['id'] | MiAnnouncement & { isRead?: boolean | null }, + me: { id: MiUser['id'] } | null | undefined, + ): Promise> { + const announcement = typeof src === 'object' + ? src + : await this.announcementsRepository.findOneByOrFail({ + id: src, + }) as MiAnnouncement & { isRead?: boolean | null }; + + if (me && announcement.isRead === undefined) { + announcement.isRead = await this.announcementReadsRepository + .countBy({ + announcementId: announcement.id, + userId: me.id, + }) + .then((count: number) => count > 0); + } + + return { + id: announcement.id, + createdAt: this.idService.parse(announcement.id).date.toISOString(), + updatedAt: announcement.updatedAt?.toISOString() ?? null, + title: announcement.title, + text: announcement.text, + imageUrl: announcement.imageUrl, + icon: announcement.icon, + display: announcement.display, + forYou: announcement.userId === me?.id, + needConfirmationToRead: announcement.needConfirmationToRead, + closeDuration: announcement.closeDuration, + displayOrder: announcement.displayOrder, + silence: announcement.silence, + isRead: announcement.isRead !== null ? announcement.isRead : undefined, + }; + } + + @bindThis + public async packMany( + announcements: (MiAnnouncement['id'] | MiAnnouncement & { isRead?: boolean | null } | MiAnnouncement)[], + me: { id: MiUser['id'] } | null | undefined, + ) : Promise[]> { + return (await Promise.allSettled(announcements.map(x => this.pack(x, me)))) + .filter(result => result.status === 'fulfilled') + .map(result => (result as PromiseFulfilledResult>).value); + } +} diff --git a/packages/backend/src/models/AbuseReportResolver.ts b/packages/backend/src/models/AbuseReportResolver.ts index 47dc4f1e5..e3174068f 100644 --- a/packages/backend/src/models/AbuseReportResolver.ts +++ b/packages/backend/src/models/AbuseReportResolver.ts @@ -13,7 +13,8 @@ export class MiAbuseReportResolver { @Index() @Column('timestamp with time zone', { - comment: 'The created date of AbuseReportResolver', + comment: 'The created date of the AbuseReportResolver.', + default: () => 'CURRENT_TIMESTAMP', }) public createdAt: Date; diff --git a/packages/backend/src/models/AbuseUserReport.ts b/packages/backend/src/models/AbuseUserReport.ts index 593c44f66..17491595c 100644 --- a/packages/backend/src/models/AbuseUserReport.ts +++ b/packages/backend/src/models/AbuseUserReport.ts @@ -12,6 +12,13 @@ export class MiAbuseUserReport { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the AbuseUserReport.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column(id()) public targetUserId: MiUser['id']; diff --git a/packages/backend/src/models/AccessToken.ts b/packages/backend/src/models/AccessToken.ts index 452711eb8..66bf626ac 100644 --- a/packages/backend/src/models/AccessToken.ts +++ b/packages/backend/src/models/AccessToken.ts @@ -13,6 +13,13 @@ export class MiAccessToken { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the AccessToken.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Column('timestamp with time zone', { nullable: true, }) diff --git a/packages/backend/src/models/Ad.ts b/packages/backend/src/models/Ad.ts index b1d7d7d79..95afe9ade 100644 --- a/packages/backend/src/models/Ad.ts +++ b/packages/backend/src/models/Ad.ts @@ -11,6 +11,13 @@ export class MiAd { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the Ad.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column('timestamp with time zone', { comment: 'The expired date of the Ad.', diff --git a/packages/backend/src/models/Announcement.ts b/packages/backend/src/models/Announcement.ts index 54f23ee8b..140a9fe18 100644 --- a/packages/backend/src/models/Announcement.ts +++ b/packages/backend/src/models/Announcement.ts @@ -12,6 +12,13 @@ export class MiAnnouncement { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the Announcement.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Column('timestamp with time zone', { comment: 'The updated date of the Announcement.', nullable: true, diff --git a/packages/backend/src/models/AnnouncementRead.ts b/packages/backend/src/models/AnnouncementRead.ts index db09e65f5..a2a696c3d 100644 --- a/packages/backend/src/models/AnnouncementRead.ts +++ b/packages/backend/src/models/AnnouncementRead.ts @@ -14,6 +14,13 @@ export class MiAnnouncementRead { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the AnnouncementRead.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column(id()) public userId: MiUser['id']; diff --git a/packages/backend/src/models/Antenna.ts b/packages/backend/src/models/Antenna.ts index b74c61b72..2e58e1ee6 100644 --- a/packages/backend/src/models/Antenna.ts +++ b/packages/backend/src/models/Antenna.ts @@ -13,6 +13,13 @@ export class MiAntenna { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the Antenna.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column('timestamp with time zone') public lastUsedAt: Date; diff --git a/packages/backend/src/models/App.ts b/packages/backend/src/models/App.ts index 5c56a224a..1f6f419b2 100644 --- a/packages/backend/src/models/App.ts +++ b/packages/backend/src/models/App.ts @@ -12,6 +12,13 @@ export class MiApp { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the App.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column({ ...id(), diff --git a/packages/backend/src/models/AuthSession.ts b/packages/backend/src/models/AuthSession.ts index 81bed2121..5b1ab4097 100644 --- a/packages/backend/src/models/AuthSession.ts +++ b/packages/backend/src/models/AuthSession.ts @@ -13,6 +13,13 @@ export class MiAuthSession { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the AuthSession.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column('varchar', { length: 128, diff --git a/packages/backend/src/models/AvatarDecoration.ts b/packages/backend/src/models/AvatarDecoration.ts index 08ebbdeac..5a723edff 100644 --- a/packages/backend/src/models/AvatarDecoration.ts +++ b/packages/backend/src/models/AvatarDecoration.ts @@ -11,6 +11,13 @@ export class MiAvatarDecoration { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the AvatarDecoration.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Column('timestamp with time zone', { nullable: true, }) diff --git a/packages/backend/src/models/Blocking.ts b/packages/backend/src/models/Blocking.ts index 9bf7a63b6..3c812c8f3 100644 --- a/packages/backend/src/models/Blocking.ts +++ b/packages/backend/src/models/Blocking.ts @@ -13,6 +13,13 @@ export class MiBlocking { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the Blocking.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column({ ...id(), diff --git a/packages/backend/src/models/Channel.ts b/packages/backend/src/models/Channel.ts index a7f9e262b..a45f34013 100644 --- a/packages/backend/src/models/Channel.ts +++ b/packages/backend/src/models/Channel.ts @@ -13,6 +13,13 @@ export class MiChannel { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the Channel.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column('timestamp with time zone', { nullable: true, diff --git a/packages/backend/src/models/ChannelFavorite.ts b/packages/backend/src/models/ChannelFavorite.ts index fc25ffe26..33bdeb862 100644 --- a/packages/backend/src/models/ChannelFavorite.ts +++ b/packages/backend/src/models/ChannelFavorite.ts @@ -14,6 +14,13 @@ export class MiChannelFavorite { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the ChannelFavorite.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column({ ...id(), diff --git a/packages/backend/src/models/ChannelFollowing.ts b/packages/backend/src/models/ChannelFollowing.ts index 4dd391a08..02aae0ab4 100644 --- a/packages/backend/src/models/ChannelFollowing.ts +++ b/packages/backend/src/models/ChannelFollowing.ts @@ -14,6 +14,13 @@ export class MiChannelFollowing { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the ChannelFollowing.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column({ ...id(), diff --git a/packages/backend/src/models/Clip.ts b/packages/backend/src/models/Clip.ts index 2483b0925..27b7cde4f 100644 --- a/packages/backend/src/models/Clip.ts +++ b/packages/backend/src/models/Clip.ts @@ -12,6 +12,13 @@ export class MiClip { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the Clip.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column('timestamp with time zone', { nullable: true, diff --git a/packages/backend/src/models/ClipFavorite.ts b/packages/backend/src/models/ClipFavorite.ts index aa949b3ea..4c9dd7321 100644 --- a/packages/backend/src/models/ClipFavorite.ts +++ b/packages/backend/src/models/ClipFavorite.ts @@ -14,6 +14,13 @@ export class MiClipFavorite { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the ClipFavorite.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column(id()) public userId: MiUser['id']; diff --git a/packages/backend/src/models/DriveFile.ts b/packages/backend/src/models/DriveFile.ts index 24e6be9c9..84cc003a4 100644 --- a/packages/backend/src/models/DriveFile.ts +++ b/packages/backend/src/models/DriveFile.ts @@ -14,6 +14,13 @@ export class MiDriveFile { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the DriveFile.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column({ ...id(), diff --git a/packages/backend/src/models/DriveFolder.ts b/packages/backend/src/models/DriveFolder.ts index 18f6d1770..73347c7b2 100644 --- a/packages/backend/src/models/DriveFolder.ts +++ b/packages/backend/src/models/DriveFolder.ts @@ -12,6 +12,13 @@ export class MiDriveFolder { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the DriveFolder.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Column('varchar', { length: 128, comment: 'The name of the DriveFolder.', diff --git a/packages/backend/src/models/Flash.ts b/packages/backend/src/models/Flash.ts index ac880843b..b89065f64 100644 --- a/packages/backend/src/models/Flash.ts +++ b/packages/backend/src/models/Flash.ts @@ -12,6 +12,13 @@ export class MiFlash { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the Flash.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column('timestamp with time zone', { comment: 'The updated date of the Flash.', diff --git a/packages/backend/src/models/FlashLike.ts b/packages/backend/src/models/FlashLike.ts index ad7f4966b..9b3a52e42 100644 --- a/packages/backend/src/models/FlashLike.ts +++ b/packages/backend/src/models/FlashLike.ts @@ -14,6 +14,13 @@ export class MiFlashLike { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the FlashLike.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column(id()) public userId: MiUser['id']; diff --git a/packages/backend/src/models/FollowRequest.ts b/packages/backend/src/models/FollowRequest.ts index 9899694dd..39ba50450 100644 --- a/packages/backend/src/models/FollowRequest.ts +++ b/packages/backend/src/models/FollowRequest.ts @@ -13,6 +13,13 @@ export class MiFollowRequest { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the FollowRequest.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column({ ...id(), diff --git a/packages/backend/src/models/Following.ts b/packages/backend/src/models/Following.ts index e320911a1..8ce333df2 100644 --- a/packages/backend/src/models/Following.ts +++ b/packages/backend/src/models/Following.ts @@ -14,6 +14,13 @@ export class MiFollowing { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the Following.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column({ ...id(), diff --git a/packages/backend/src/models/GalleryLike.ts b/packages/backend/src/models/GalleryLike.ts index 84d4ce9c3..ab9b2a32a 100644 --- a/packages/backend/src/models/GalleryLike.ts +++ b/packages/backend/src/models/GalleryLike.ts @@ -14,6 +14,13 @@ export class MiGalleryLike { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the GalleryLike.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column(id()) public userId: MiUser['id']; diff --git a/packages/backend/src/models/GalleryPost.ts b/packages/backend/src/models/GalleryPost.ts index b72220caf..ea7d4320b 100644 --- a/packages/backend/src/models/GalleryPost.ts +++ b/packages/backend/src/models/GalleryPost.ts @@ -13,6 +13,13 @@ export class MiGalleryPost { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the GalleryPost.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column('timestamp with time zone', { comment: 'The updated date of the GalleryPost.', diff --git a/packages/backend/src/models/ModerationLog.ts b/packages/backend/src/models/ModerationLog.ts index 71b33c3e4..b1ca16291 100644 --- a/packages/backend/src/models/ModerationLog.ts +++ b/packages/backend/src/models/ModerationLog.ts @@ -12,6 +12,13 @@ export class MiModerationLog { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the ModerationLog.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column(id()) public userId: MiUser['id']; diff --git a/packages/backend/src/models/Muting.ts b/packages/backend/src/models/Muting.ts index a528e1e7d..76655f55d 100644 --- a/packages/backend/src/models/Muting.ts +++ b/packages/backend/src/models/Muting.ts @@ -13,6 +13,13 @@ export class MiMuting { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the Muting.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column('timestamp with time zone', { nullable: true, diff --git a/packages/backend/src/models/Note.ts b/packages/backend/src/models/Note.ts index a4358b9ba..8bb794d46 100644 --- a/packages/backend/src/models/Note.ts +++ b/packages/backend/src/models/Note.ts @@ -18,6 +18,13 @@ export class MiNote { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the Note.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column({ ...id(), diff --git a/packages/backend/src/models/NoteFavorite.ts b/packages/backend/src/models/NoteFavorite.ts index 364eaabd9..0790b26fc 100644 --- a/packages/backend/src/models/NoteFavorite.ts +++ b/packages/backend/src/models/NoteFavorite.ts @@ -14,6 +14,13 @@ export class MiNoteFavorite { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the NoteFavorite.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column(id()) public userId: MiUser['id']; diff --git a/packages/backend/src/models/NoteReaction.ts b/packages/backend/src/models/NoteReaction.ts index ee3a44746..f71574bb5 100644 --- a/packages/backend/src/models/NoteReaction.ts +++ b/packages/backend/src/models/NoteReaction.ts @@ -14,6 +14,13 @@ export class MiNoteReaction { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the NoteReaction.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column(id()) public userId: MiUser['id']; diff --git a/packages/backend/src/models/NoteThreadMuting.ts b/packages/backend/src/models/NoteThreadMuting.ts index 00311aa57..e2e1d95eb 100644 --- a/packages/backend/src/models/NoteThreadMuting.ts +++ b/packages/backend/src/models/NoteThreadMuting.ts @@ -13,6 +13,13 @@ export class MiNoteThreadMuting { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the NoteThreadMuting.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column({ ...id(), diff --git a/packages/backend/src/models/Page.ts b/packages/backend/src/models/Page.ts index 9cab87549..7b5248464 100644 --- a/packages/backend/src/models/Page.ts +++ b/packages/backend/src/models/Page.ts @@ -14,6 +14,13 @@ export class MiPage { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the Page.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column('timestamp with time zone', { comment: 'The updated date of the Page.', diff --git a/packages/backend/src/models/PageLike.ts b/packages/backend/src/models/PageLike.ts index b845f58b7..8e866284e 100644 --- a/packages/backend/src/models/PageLike.ts +++ b/packages/backend/src/models/PageLike.ts @@ -14,6 +14,13 @@ export class MiPageLike { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the PageLike.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column(id()) public userId: MiUser['id']; diff --git a/packages/backend/src/models/PasswordResetRequest.ts b/packages/backend/src/models/PasswordResetRequest.ts index 5be439511..ec856b14f 100644 --- a/packages/backend/src/models/PasswordResetRequest.ts +++ b/packages/backend/src/models/PasswordResetRequest.ts @@ -12,6 +12,13 @@ export class MiPasswordResetRequest { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the PasswordResetRequest.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index({ unique: true }) @Column('varchar', { length: 256, diff --git a/packages/backend/src/models/PollVote.ts b/packages/backend/src/models/PollVote.ts index 751be8a32..777bc3c7b 100644 --- a/packages/backend/src/models/PollVote.ts +++ b/packages/backend/src/models/PollVote.ts @@ -14,6 +14,13 @@ export class MiPollVote { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the PollVote.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column(id()) public userId: MiUser['id']; diff --git a/packages/backend/src/models/PromoRead.ts b/packages/backend/src/models/PromoRead.ts index d9f307541..4b617b569 100644 --- a/packages/backend/src/models/PromoRead.ts +++ b/packages/backend/src/models/PromoRead.ts @@ -14,6 +14,13 @@ export class MiPromoRead { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the PromoRead.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column(id()) public userId: MiUser['id']; diff --git a/packages/backend/src/models/RegistrationTicket.ts b/packages/backend/src/models/RegistrationTicket.ts index 730cedffb..d19d280da 100644 --- a/packages/backend/src/models/RegistrationTicket.ts +++ b/packages/backend/src/models/RegistrationTicket.ts @@ -12,6 +12,13 @@ export class MiRegistrationTicket { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the RegistrationTicket.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index({ unique: true }) @Column('varchar', { length: 64, diff --git a/packages/backend/src/models/RegistryItem.ts b/packages/backend/src/models/RegistryItem.ts index 60bdced95..5388a166c 100644 --- a/packages/backend/src/models/RegistryItem.ts +++ b/packages/backend/src/models/RegistryItem.ts @@ -13,6 +13,13 @@ export class MiRegistryItem { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the RegistryItem.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Column('timestamp with time zone', { comment: 'The updated date of the RegistryItem.', }) diff --git a/packages/backend/src/models/RenoteMuting.ts b/packages/backend/src/models/RenoteMuting.ts index 17df43ea3..1f86255b9 100644 --- a/packages/backend/src/models/RenoteMuting.ts +++ b/packages/backend/src/models/RenoteMuting.ts @@ -13,6 +13,13 @@ export class MiRenoteMuting { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the RenoteMuting.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column({ ...id(), diff --git a/packages/backend/src/models/RetentionAggregation.ts b/packages/backend/src/models/RetentionAggregation.ts index 9da401597..85811baec 100644 --- a/packages/backend/src/models/RetentionAggregation.ts +++ b/packages/backend/src/models/RetentionAggregation.ts @@ -14,7 +14,8 @@ export class MiRetentionAggregation { @Index() @Column('timestamp with time zone', { - comment: 'The created date of the Note.', + comment: 'The created date of the GalleryPost.', + default: () => 'CURRENT_TIMESTAMP', }) public createdAt: Date; diff --git a/packages/backend/src/models/Role.ts b/packages/backend/src/models/Role.ts index 6976956e1..0839dd85f 100644 --- a/packages/backend/src/models/Role.ts +++ b/packages/backend/src/models/Role.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { Entity, Column, PrimaryColumn } from 'typeorm'; +import { Entity, Column, PrimaryColumn, Index } from 'typeorm'; import { id } from './util/id.js'; type CondFormulaValueAnd = { @@ -89,6 +89,13 @@ export class MiRole { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the Role.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Column('timestamp with time zone', { comment: 'The updated date of the Role.', }) diff --git a/packages/backend/src/models/RoleAssignment.ts b/packages/backend/src/models/RoleAssignment.ts index 30c7e19f2..5139ef84e 100644 --- a/packages/backend/src/models/RoleAssignment.ts +++ b/packages/backend/src/models/RoleAssignment.ts @@ -14,6 +14,13 @@ export class MiRoleAssignment { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the RoleAssignment.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column({ ...id(), diff --git a/packages/backend/src/models/Signin.ts b/packages/backend/src/models/Signin.ts index 656b44dfe..6472c4aaf 100644 --- a/packages/backend/src/models/Signin.ts +++ b/packages/backend/src/models/Signin.ts @@ -12,6 +12,13 @@ export class MiSignin { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the Signin.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column(id()) public userId: MiUser['id']; diff --git a/packages/backend/src/models/SwSubscription.ts b/packages/backend/src/models/SwSubscription.ts index f685a8ff3..13ad937d7 100644 --- a/packages/backend/src/models/SwSubscription.ts +++ b/packages/backend/src/models/SwSubscription.ts @@ -12,6 +12,13 @@ export class MiSwSubscription { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the SwSubscriptipnpon.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column(id()) public userId: MiUser['id']; diff --git a/packages/backend/src/models/UsedUsername.ts b/packages/backend/src/models/UsedUsername.ts index c75bf424c..3f5a96162 100644 --- a/packages/backend/src/models/UsedUsername.ts +++ b/packages/backend/src/models/UsedUsername.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { PrimaryColumn, Entity, Column } from 'typeorm'; +import { PrimaryColumn, Entity, Column, Index } from 'typeorm'; @Entity('used_username') export class MiUsedUsername { @@ -12,7 +12,11 @@ export class MiUsedUsername { }) public username: string; - @Column('timestamp with time zone') + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the UsedUsername.', + default: () => 'CURRENT_TIMESTAMP', + }) public createdAt: Date; constructor(data: Partial) { diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts index c3762fcd3..1d69bbda6 100644 --- a/packages/backend/src/models/User.ts +++ b/packages/backend/src/models/User.ts @@ -13,6 +13,13 @@ export class MiUser { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the User.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column('timestamp with time zone', { nullable: true, diff --git a/packages/backend/src/models/UserIp.ts b/packages/backend/src/models/UserIp.ts index 60a7bc8b0..f838e1ad1 100644 --- a/packages/backend/src/models/UserIp.ts +++ b/packages/backend/src/models/UserIp.ts @@ -13,7 +13,10 @@ export class MiUserIp { @PrimaryGeneratedColumn() public id: string; + @Index() @Column('timestamp with time zone', { + comment: 'The created date of the UserIp.', + default: () => 'CURRENT_TIMESTAMP', }) public createdAt: Date; diff --git a/packages/backend/src/models/UserList.ts b/packages/backend/src/models/UserList.ts index 7ad15419d..2fce93e74 100644 --- a/packages/backend/src/models/UserList.ts +++ b/packages/backend/src/models/UserList.ts @@ -12,6 +12,13 @@ export class MiUserList { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the UserList.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column({ ...id(), diff --git a/packages/backend/src/models/UserListFavorite.ts b/packages/backend/src/models/UserListFavorite.ts index a18ed9253..e095ebc53 100644 --- a/packages/backend/src/models/UserListFavorite.ts +++ b/packages/backend/src/models/UserListFavorite.ts @@ -14,6 +14,13 @@ export class MiUserListFavorite { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the UserListFavorite.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column(id()) public userId: MiUser['id']; diff --git a/packages/backend/src/models/UserListMembership.ts b/packages/backend/src/models/UserListMembership.ts index fa8287f17..a779b6355 100644 --- a/packages/backend/src/models/UserListMembership.ts +++ b/packages/backend/src/models/UserListMembership.ts @@ -14,6 +14,13 @@ export class MiUserListMembership { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the UserListMembership.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column({ ...id(), diff --git a/packages/backend/src/models/UserNotePining.ts b/packages/backend/src/models/UserNotePining.ts index ae5977aa5..630eeedf8 100644 --- a/packages/backend/src/models/UserNotePining.ts +++ b/packages/backend/src/models/UserNotePining.ts @@ -14,6 +14,13 @@ export class MiUserNotePining { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the UserNotePining.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column(id()) public userId: MiUser['id']; diff --git a/packages/backend/src/models/UserPending.ts b/packages/backend/src/models/UserPending.ts index 8b1f8f617..b4cd0e24c 100644 --- a/packages/backend/src/models/UserPending.ts +++ b/packages/backend/src/models/UserPending.ts @@ -11,6 +11,13 @@ export class MiUserPending { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the UserPending.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index({ unique: true }) @Column('varchar', { length: 128, diff --git a/packages/backend/src/models/Webhook.ts b/packages/backend/src/models/Webhook.ts index ec4e13cc7..6bf4a3407 100644 --- a/packages/backend/src/models/Webhook.ts +++ b/packages/backend/src/models/Webhook.ts @@ -14,6 +14,13 @@ export class MiWebhook { @PrimaryColumn(id()) public id: string; + @Index() + @Column('timestamp with time zone', { + comment: 'The created date of the Webhook.', + default: () => 'CURRENT_TIMESTAMP', + }) + public createdAt: Date; + @Index() @Column({ ...id(), diff --git a/packages/backend/src/models/json-schema/announcement.ts b/packages/backend/src/models/json-schema/announcement.ts index e23620e99..fdeea862e 100644 --- a/packages/backend/src/models/json-schema/announcement.ts +++ b/packages/backend/src/models/json-schema/announcement.ts @@ -58,6 +58,10 @@ export const packedAnnouncementSchema = { type: 'number', optional: false, nullable: false, }, + silence: { + type: 'boolean', + optional: false, nullable: false, + }, isRead: { type: 'boolean', optional: true, nullable: false, diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts index 1bb02b476..c790a826a 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts @@ -69,6 +69,10 @@ export const meta = { type: 'number', optional: false, nullable: false, }, + silence: { + type: 'boolean', + optional: false, nullable: false, + }, isRead: { type: 'boolean', optional: true, nullable: false, @@ -86,10 +90,10 @@ export const paramDef = { icon: { type: 'string', enum: ['info', 'warning', 'error', 'success'], default: 'info' }, display: { type: 'string', enum: ['normal', 'banner', 'dialog'], default: 'normal' }, forExistingUsers: { type: 'boolean', default: false }, - silence: { type: 'boolean', default: false }, needConfirmationToRead: { type: 'boolean', default: false }, closeDuration: { type: 'number', default: 0 }, displayOrder: { type: 'number', default: 0 }, + silence: { type: 'boolean', default: false }, userId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, }, required: ['title', 'text', 'imageUrl'], @@ -109,10 +113,10 @@ export default class extends Endpoint { // eslint- icon: ps.icon, display: ps.display, forExistingUsers: ps.forExistingUsers, - silence: ps.silence, needConfirmationToRead: ps.needConfirmationToRead, closeDuration: ps.closeDuration, displayOrder: ps.displayOrder, + silence: ps.silence, userId: ps.userId, }, me); diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts index 6b16efa30..869308f61 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts @@ -79,6 +79,10 @@ export const meta = { type: 'number', optional: false, nullable: false, }, + silence: { + type: 'boolean', + optional: false, nullable: false, + }, userId: { type: 'string', optional: false, nullable: true, @@ -128,13 +132,13 @@ export default class extends Endpoint { // eslint- display: announcement.display, isActive: announcement.isActive, forExistingUsers: announcement.forExistingUsers, - silence: announcement.silence, needConfirmationToRead: announcement.needConfirmationToRead, closeDuration: announcement.closeDuration, displayOrder: announcement.displayOrder, + silence: announcement.silence, userId: announcement.userId, user: announcement.userInfo, - reads: announcement.readCount, + reads: announcement.reads, })); }); } diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts index 04d6836fd..93176d751 100644 --- a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts +++ b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts @@ -35,10 +35,10 @@ export const paramDef = { icon: { type: 'string', enum: ['info', 'warning', 'error', 'success'] }, display: { type: 'string', enum: ['normal', 'banner', 'dialog'] }, forExistingUsers: { type: 'boolean' }, - silence: { type: 'boolean' }, needConfirmationToRead: { type: 'boolean' }, closeDuration: { type: 'number', default: 0 }, displayOrder: { type: 'number', default: 0 }, + silence: { type: 'boolean' }, isActive: { type: 'boolean' }, }, required: ['id'], @@ -66,10 +66,10 @@ export default class extends Endpoint { // eslint- display: ps.display, icon: ps.icon, forExistingUsers: ps.forExistingUsers, - silence: ps.silence, needConfirmationToRead: ps.needConfirmationToRead, closeDuration: ps.closeDuration, displayOrder: ps.displayOrder, + silence: ps.silence, isActive: ps.isActive, }, me); }); diff --git a/packages/backend/test/unit/AnnouncementService.ts b/packages/backend/test/unit/AnnouncementService.ts index f2aa5d35e..d001dc8e8 100644 --- a/packages/backend/test/unit/AnnouncementService.ts +++ b/packages/backend/test/unit/AnnouncementService.ts @@ -10,6 +10,7 @@ import { ModuleMocker } from 'jest-mock'; import { Test } from '@nestjs/testing'; import { GlobalModule } from '@/GlobalModule.js'; import { AnnouncementService } from '@/core/AnnouncementService.js'; +import { AnnouncementEntityService } from "@/core/entities/AnnouncementEntityService.js"; import type { MiAnnouncement, AnnouncementsRepository, AnnouncementReadsRepository, UsersRepository, MiUser } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; import { genAidx } from '@/misc/id/aidx.js'; @@ -61,6 +62,7 @@ describe('AnnouncementService', () => { ], providers: [ AnnouncementService, + AnnouncementEntityService, CacheService, IdService, ], diff --git a/packages/frontend/src/components/MkUserAnnouncementEditDialog.vue b/packages/frontend/src/components/MkUserAnnouncementEditDialog.vue index 3d0700cb8..fc58dac07 100644 --- a/packages/frontend/src/components/MkUserAnnouncementEditDialog.vue +++ b/packages/frontend/src/components/MkUserAnnouncementEditDialog.vue @@ -49,7 +49,11 @@ SPDX-License-Identifier: AGPL-3.0-only -

{{ i18n.t('nUsersRead', { n: readCount }) }}

+ + {{ i18n.ts._announcement.silence }} + + +

{{ i18n.t('nUsersRead', { n: reads }) }}

{{ i18n.ts.delete }} @@ -62,7 +66,6 @@ SPDX-License-Identifier: AGPL-3.0-only