enhance(backend): DBのコラム設定としてcreatedAtの値を入れるように/お知らせ機能API修正

This commit is contained in:
まっちゃとーにゅ 2023-11-20 06:04:59 +09:00
parent 455c7eb653
commit 2883f28b87
No known key found for this signature in database
GPG key ID: 6AFBBF529601C1DB
71 changed files with 730 additions and 219 deletions

View file

@ -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") `);
}
}

View file

@ -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"`);
}
}

View file

@ -12,9 +12,10 @@ import { MiAnnouncementRead } from '@/models/_.js';
import { bindThis } from '@/decorators.js'; import { bindThis } from '@/decorators.js';
import { Packed } from '@/misc/json-schema.js'; import { Packed } from '@/misc/json-schema.js';
import { IdService } from '@/core/IdService.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 { GlobalEventService } from '@/core/GlobalEventService.js';
import { ModerationLogService } from '@/core/ModerationLogService.js'; import { ModerationLogService } from '@/core/ModerationLogService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
@Injectable() @Injectable()
export class AnnouncementService { export class AnnouncementService {
@ -30,6 +31,7 @@ export class AnnouncementService {
private idService: IdService, private idService: IdService,
private userEntityService: UserEntityService, private userEntityService: UserEntityService,
private announcementEntityService: AnnouncementEntityService,
private globalEventService: GlobalEventService, private globalEventService: GlobalEventService,
private moderationLogService: ModerationLogService, private moderationLogService: ModerationLogService,
) { ) {
@ -45,7 +47,7 @@ export class AnnouncementService {
@bindThis @bindThis
public async getUnreadAnnouncements(user: MiUser): Promise<Packed<'Announcement'>[]> { public async getUnreadAnnouncements(user: MiUser): Promise<Packed<'Announcement'>[]> {
const q = this.announcementsRepository.createQueryBuilder('announcement'); const q = this.announcementsRepository.createQueryBuilder('announcement');
q.leftJoin( q.leftJoinAndSelect(
MiAnnouncementRead, MiAnnouncementRead,
'read', 'read',
'read."announcementId" = announcement.id AND read."userId" = :userId', 'read."announcementId" = announcement.id AND read."userId" = :userId',
@ -53,7 +55,8 @@ export class AnnouncementService {
); );
q q
.where('announcement.isActive = true') .where('read.id IS NULL')
.andWhere('announcement.isActive = true')
.andWhere('announcement.silence = false') .andWhere('announcement.silence = false')
.andWhere(new Brackets(qb => { .andWhere(new Brackets(qb => {
qb.orWhere('announcement.userId = :userId', { userId: user.id }); qb.orWhere('announcement.userId = :userId', { userId: user.id });
@ -62,15 +65,14 @@ export class AnnouncementService {
.andWhere(new Brackets(qb => { .andWhere(new Brackets(qb => {
qb.orWhere('announcement.forExistingUsers = false'); qb.orWhere('announcement.forExistingUsers = false');
qb.orWhere('announcement.id > :userId', { userId: user.id }); qb.orWhere('announcement.id > :userId', { userId: user.id });
})) }));
.andWhere('read.id IS NULL');
q.orderBy({ q.orderBy({
'announcement."displayOrder"': 'DESC', 'announcement."displayOrder"': 'DESC',
'announcement.id': 'DESC', 'announcement.id': 'DESC',
}); });
return this.packMany( return this.announcementEntityService.packMany(
await q.getMany(), await q.getMany(),
user, user,
); );
@ -94,7 +96,7 @@ export class AnnouncementService {
userId: values.userId, userId: values.userId,
}).then(x => this.announcementsRepository.findOneByOrFail(x.identifiers[0])); }).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) { if (values.userId) {
this.globalEventService.publishMainStream(values.userId, 'announcementCreated', { this.globalEventService.publishMainStream(values.userId, 'announcementCreated', {
@ -136,7 +138,7 @@ export class AnnouncementService {
limit: number, limit: number,
offset: number, offset: number,
moderator: MiUser, moderator: MiUser,
): Promise<(MiAnnouncement & { userInfo: Packed<'UserLite'> | null, readCount: number })[]> { ): Promise<(MiAnnouncement & { userInfo: Packed<'UserLite'> | null, reads: number })[]> {
const query = this.announcementsRepository.createQueryBuilder('announcement'); const query = this.announcementsRepository.createQueryBuilder('announcement');
if (userId) { if (userId) {
query.andWhere('announcement."userId" = :userId', { userId: userId }); query.andWhere('announcement."userId" = :userId', { userId: userId });
@ -173,7 +175,7 @@ export class AnnouncementService {
return announcements.map(announcement => ({ return announcements.map(announcement => ({
...announcement, ...announcement,
userInfo: packedUsers.find(u => u.id === announcement.userId) ?? null, 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, { await this.announcementsRepository.update(announcement.id, {
updatedAt: new Date(), updatedAt: new Date(),
isActive: values.isActive,
title: values.title, title: values.title,
text: values.text, text: values.text,
/* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- 空の文字列の場合、nullを渡すようにするため */ /* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- 空の文字列の場合、nullを渡すようにするため */
@ -195,11 +198,10 @@ export class AnnouncementService {
display: values.display, display: values.display,
icon: values.icon, icon: values.icon,
forExistingUsers: values.forExistingUsers, forExistingUsers: values.forExistingUsers,
silence: values.silence,
needConfirmationToRead: values.needConfirmationToRead, needConfirmationToRead: values.needConfirmationToRead,
closeDuration: values.closeDuration, closeDuration: values.closeDuration,
displayOrder: values.displayOrder, displayOrder: values.displayOrder,
isActive: values.isActive, silence: values.silence,
userId: values.userId, userId: values.userId,
}); });
@ -305,7 +307,7 @@ export class AnnouncementService {
'announcement.id': 'DESC', 'announcement.id': 'DESC',
}); });
return this.packMany( return this.announcementEntityService.packMany(
await query await query
.limit(limit) .limit(limit)
.offset(offset) .offset(offset)
@ -315,32 +317,29 @@ export class AnnouncementService {
} }
@bindThis @bindThis
public async countUnreadAnnouncements(me: MiUser): Promise<number> { public async countUnreadAnnouncements(user: MiUser): Promise<number> {
const query = this.announcementsRepository.createQueryBuilder('announcement'); const q = this.announcementsRepository.createQueryBuilder('announcement');
query.leftJoinAndSelect( q.leftJoinAndSelect(
MiAnnouncementRead, MiAnnouncementRead,
'read', 'read',
'read."announcementId" = announcement.id AND read."userId" = :userId', '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 });
}),
); );
return query.getCount(); 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 q.getCount();
} }
@bindThis @bindThis
@ -359,27 +358,4 @@ export class AnnouncementService {
this.globalEventService.publishMainStream(user.id, 'readAllAnnouncements'); this.globalEventService.publishMainStream(user.id, 'readAllAnnouncements');
} }
} }
@bindThis
public async packMany(
announcements: (MiAnnouncement & { isRead?: boolean | null })[],
me: { id: MiUser['id'] } | null | undefined,
): Promise<Packed<'Announcement'>[]> {
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,
}));
}
} }

View file

@ -57,12 +57,14 @@ export class AntennaService implements OnApplicationShutdown {
case 'antennaCreated': case 'antennaCreated':
this.antennas.push({ this.antennas.push({
...body, ...body,
createdAt: new Date(body.createdAt),
lastUsedAt: new Date(body.lastUsedAt), lastUsedAt: new Date(body.lastUsedAt),
}); });
break; break;
case 'antennaUpdated': case 'antennaUpdated':
this.antennas[this.antennas.findIndex(a => a.id === body.id)] = { this.antennas[this.antennas.findIndex(a => a.id === body.id)] = {
...body, ...body,
createdAt: new Date(body.createdAt),
lastUsedAt: new Date(body.lastUsedAt), lastUsedAt: new Date(body.lastUsedAt),
}; };
break; break;

View file

@ -80,6 +80,7 @@ import PerUserDriveChart from './chart/charts/per-user-drive.js';
import ApRequestChart from './chart/charts/ap-request.js'; import ApRequestChart from './chart/charts/ap-request.js';
import { ChartManagementService } from './chart/ChartManagementService.js'; import { ChartManagementService } from './chart/ChartManagementService.js';
import { AbuseUserReportEntityService } from './entities/AbuseUserReportEntityService.js'; import { AbuseUserReportEntityService } from './entities/AbuseUserReportEntityService.js';
import { AnnouncementEntityService } from './entities/AnnouncementEntityService.js';
import { AntennaEntityService } from './entities/AntennaEntityService.js'; import { AntennaEntityService } from './entities/AntennaEntityService.js';
import { AppEntityService } from './entities/AppEntityService.js'; import { AppEntityService } from './entities/AppEntityService.js';
import { AuthSessionEntityService } from './entities/AuthSessionEntityService.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 $ChartManagementService: Provider = { provide: 'ChartManagementService', useExisting: ChartManagementService };
const $AbuseUserReportEntityService: Provider = { provide: 'AbuseUserReportEntityService', useExisting: AbuseUserReportEntityService }; const $AbuseUserReportEntityService: Provider = { provide: 'AbuseUserReportEntityService', useExisting: AbuseUserReportEntityService };
const $AnnouncementEntityService: Provider = { provide: 'AnnouncementEntityService', useExisting: AnnouncementEntityService };
const $AntennaEntityService: Provider = { provide: 'AntennaEntityService', useExisting: AntennaEntityService }; const $AntennaEntityService: Provider = { provide: 'AntennaEntityService', useExisting: AntennaEntityService };
const $AppEntityService: Provider = { provide: 'AppEntityService', useExisting: AppEntityService }; const $AppEntityService: Provider = { provide: 'AppEntityService', useExisting: AppEntityService };
const $AuthSessionEntityService: Provider = { provide: 'AuthSessionEntityService', useExisting: AuthSessionEntityService }; const $AuthSessionEntityService: Provider = { provide: 'AuthSessionEntityService', useExisting: AuthSessionEntityService };
@ -348,6 +350,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
ApRequestChart, ApRequestChart,
ChartManagementService, ChartManagementService,
AbuseUserReportEntityService, AbuseUserReportEntityService,
AnnouncementEntityService,
AntennaEntityService, AntennaEntityService,
AppEntityService, AppEntityService,
AuthSessionEntityService, AuthSessionEntityService,
@ -477,6 +480,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$ApRequestChart, $ApRequestChart,
$ChartManagementService, $ChartManagementService,
$AbuseUserReportEntityService, $AbuseUserReportEntityService,
$AnnouncementEntityService,
$AntennaEntityService, $AntennaEntityService,
$AppEntityService, $AppEntityService,
$AuthSessionEntityService, $AuthSessionEntityService,
@ -606,6 +610,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
ApRequestChart, ApRequestChart,
ChartManagementService, ChartManagementService,
AbuseUserReportEntityService, AbuseUserReportEntityService,
AnnouncementEntityService,
AntennaEntityService, AntennaEntityService,
AppEntityService, AppEntityService,
AuthSessionEntityService, AuthSessionEntityService,
@ -734,6 +739,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
$ApRequestChart, $ApRequestChart,
$ChartManagementService, $ChartManagementService,
$AbuseUserReportEntityService, $AbuseUserReportEntityService,
$AnnouncementEntityService,
$AntennaEntityService, $AntennaEntityService,
$AppEntityService, $AppEntityService,
$AuthSessionEntityService, $AuthSessionEntityService,

View file

@ -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[]) { private async insertNote(user: { id: MiUser['id']; host: MiUser['host']; }, data: Option, tags: string[], emojis: string[], mentionedUsers: MinimumUser[]) {
const insert = new MiNote({ const insert = new MiNote({
id: this.idService.gen(data.createdAt?.getTime()), id: this.idService.gen(data.createdAt?.getTime()),
createdAt: data.createdAt!,
fileIds: data.files ? data.files.map(file => file.id) : [], fileIds: data.files ? data.files.map(file => file.id) : [],
replyId: data.reply ? data.reply.id : null, replyId: data.reply ? data.reply.id : null,
renoteId: data.renote ? data.renote.id : null, renoteId: data.renote ? data.renote.id : null,

View file

@ -158,6 +158,7 @@ export class ReactionService {
const record: MiNoteReaction = { const record: MiNoteReaction = {
id: this.idService.gen(), id: this.idService.gen(),
createdAt: new Date(),
noteId: note.id, noteId: note.id,
userId: user.id, userId: user.id,
reaction, reaction,

View file

@ -131,6 +131,7 @@ export class RoleService implements OnApplicationShutdown {
if (cached) { if (cached) {
cached.push({ cached.push({
...body, ...body,
createdAt: new Date(body.createdAt),
updatedAt: new Date(body.updatedAt), updatedAt: new Date(body.updatedAt),
lastUsedAt: new Date(body.lastUsedAt), lastUsedAt: new Date(body.lastUsedAt),
}); });
@ -144,6 +145,7 @@ export class RoleService implements OnApplicationShutdown {
if (i > -1) { if (i > -1) {
cached[i] = { cached[i] = {
...body, ...body,
createdAt: new Date(body.createdAt),
updatedAt: new Date(body.updatedAt), updatedAt: new Date(body.updatedAt),
lastUsedAt: new Date(body.lastUsedAt), lastUsedAt: new Date(body.lastUsedAt),
}; };
@ -163,6 +165,7 @@ export class RoleService implements OnApplicationShutdown {
if (cached) { if (cached) {
cached.push({ cached.push({
...body, ...body,
createdAt: new Date(body.createdAt),
expiresAt: body.expiresAt ? new Date(body.expiresAt) : null, expiresAt: body.expiresAt ? new Date(body.expiresAt) : null,
}); });
} }

View file

@ -51,6 +51,7 @@ export class WebhookService implements OnApplicationShutdown {
if (body.active) { if (body.active) {
this.webhooks.push({ this.webhooks.push({
...body, ...body,
createdAt: new Date(body.createdAt),
latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null, latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null,
}); });
} }
@ -61,11 +62,13 @@ export class WebhookService implements OnApplicationShutdown {
if (i > -1) { if (i > -1) {
this.webhooks[i] = { this.webhooks[i] = {
...body, ...body,
createdAt: new Date(body.createdAt),
latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null, latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null,
}; };
} else { } else {
this.webhooks.push({ this.webhooks.push({
...body, ...body,
createdAt: new Date(body.createdAt),
latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null, latestSentAt: body.latestSentAt ? new Date(body.latestSentAt) : null,
}); });
} }

View file

@ -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<Packed<'Announcement'>> {
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<Packed<'Announcement'>[]> {
return (await Promise.allSettled(announcements.map(x => this.pack(x, me))))
.filter(result => result.status === 'fulfilled')
.map(result => (result as PromiseFulfilledResult<Packed<'Announcement'>>).value);
}
}

View file

@ -13,7 +13,8 @@ export class MiAbuseReportResolver {
@Index() @Index()
@Column('timestamp with time zone', { @Column('timestamp with time zone', {
comment: 'The created date of AbuseReportResolver', comment: 'The created date of the AbuseReportResolver.',
default: () => 'CURRENT_TIMESTAMP',
}) })
public createdAt: Date; public createdAt: Date;

View file

@ -12,6 +12,13 @@ export class MiAbuseUserReport {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the AbuseUserReport.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column(id()) @Column(id())
public targetUserId: MiUser['id']; public targetUserId: MiUser['id'];

View file

@ -13,6 +13,13 @@ export class MiAccessToken {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; 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', { @Column('timestamp with time zone', {
nullable: true, nullable: true,
}) })

View file

@ -11,6 +11,13 @@ export class MiAd {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the Ad.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column('timestamp with time zone', { @Column('timestamp with time zone', {
comment: 'The expired date of the Ad.', comment: 'The expired date of the Ad.',

View file

@ -12,6 +12,13 @@ export class MiAnnouncement {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; 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', { @Column('timestamp with time zone', {
comment: 'The updated date of the Announcement.', comment: 'The updated date of the Announcement.',
nullable: true, nullable: true,

View file

@ -14,6 +14,13 @@ export class MiAnnouncementRead {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the AnnouncementRead.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column(id()) @Column(id())
public userId: MiUser['id']; public userId: MiUser['id'];

View file

@ -13,6 +13,13 @@ export class MiAntenna {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the Antenna.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column('timestamp with time zone') @Column('timestamp with time zone')
public lastUsedAt: Date; public lastUsedAt: Date;

View file

@ -12,6 +12,13 @@ export class MiApp {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the App.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column({ @Column({
...id(), ...id(),

View file

@ -13,6 +13,13 @@ export class MiAuthSession {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the AuthSession.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column('varchar', { @Column('varchar', {
length: 128, length: 128,

View file

@ -11,6 +11,13 @@ export class MiAvatarDecoration {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; 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', { @Column('timestamp with time zone', {
nullable: true, nullable: true,
}) })

View file

@ -13,6 +13,13 @@ export class MiBlocking {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the Blocking.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column({ @Column({
...id(), ...id(),

View file

@ -13,6 +13,13 @@ export class MiChannel {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the Channel.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column('timestamp with time zone', { @Column('timestamp with time zone', {
nullable: true, nullable: true,

View file

@ -14,6 +14,13 @@ export class MiChannelFavorite {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the ChannelFavorite.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column({ @Column({
...id(), ...id(),

View file

@ -14,6 +14,13 @@ export class MiChannelFollowing {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the ChannelFollowing.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column({ @Column({
...id(), ...id(),

View file

@ -12,6 +12,13 @@ export class MiClip {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the Clip.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column('timestamp with time zone', { @Column('timestamp with time zone', {
nullable: true, nullable: true,

View file

@ -14,6 +14,13 @@ export class MiClipFavorite {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the ClipFavorite.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column(id()) @Column(id())
public userId: MiUser['id']; public userId: MiUser['id'];

View file

@ -14,6 +14,13 @@ export class MiDriveFile {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the DriveFile.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column({ @Column({
...id(), ...id(),

View file

@ -12,6 +12,13 @@ export class MiDriveFolder {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the DriveFolder.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Column('varchar', { @Column('varchar', {
length: 128, length: 128,
comment: 'The name of the DriveFolder.', comment: 'The name of the DriveFolder.',

View file

@ -12,6 +12,13 @@ export class MiFlash {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the Flash.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column('timestamp with time zone', { @Column('timestamp with time zone', {
comment: 'The updated date of the Flash.', comment: 'The updated date of the Flash.',

View file

@ -14,6 +14,13 @@ export class MiFlashLike {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the FlashLike.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column(id()) @Column(id())
public userId: MiUser['id']; public userId: MiUser['id'];

View file

@ -13,6 +13,13 @@ export class MiFollowRequest {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the FollowRequest.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column({ @Column({
...id(), ...id(),

View file

@ -14,6 +14,13 @@ export class MiFollowing {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the Following.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column({ @Column({
...id(), ...id(),

View file

@ -14,6 +14,13 @@ export class MiGalleryLike {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the GalleryLike.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column(id()) @Column(id())
public userId: MiUser['id']; public userId: MiUser['id'];

View file

@ -13,6 +13,13 @@ export class MiGalleryPost {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the GalleryPost.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column('timestamp with time zone', { @Column('timestamp with time zone', {
comment: 'The updated date of the GalleryPost.', comment: 'The updated date of the GalleryPost.',

View file

@ -12,6 +12,13 @@ export class MiModerationLog {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the ModerationLog.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column(id()) @Column(id())
public userId: MiUser['id']; public userId: MiUser['id'];

View file

@ -13,6 +13,13 @@ export class MiMuting {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the Muting.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column('timestamp with time zone', { @Column('timestamp with time zone', {
nullable: true, nullable: true,

View file

@ -18,6 +18,13 @@ export class MiNote {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the Note.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column({ @Column({
...id(), ...id(),

View file

@ -14,6 +14,13 @@ export class MiNoteFavorite {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the NoteFavorite.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column(id()) @Column(id())
public userId: MiUser['id']; public userId: MiUser['id'];

View file

@ -14,6 +14,13 @@ export class MiNoteReaction {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the NoteReaction.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column(id()) @Column(id())
public userId: MiUser['id']; public userId: MiUser['id'];

View file

@ -13,6 +13,13 @@ export class MiNoteThreadMuting {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the NoteThreadMuting.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column({ @Column({
...id(), ...id(),

View file

@ -14,6 +14,13 @@ export class MiPage {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the Page.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column('timestamp with time zone', { @Column('timestamp with time zone', {
comment: 'The updated date of the Page.', comment: 'The updated date of the Page.',

View file

@ -14,6 +14,13 @@ export class MiPageLike {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the PageLike.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column(id()) @Column(id())
public userId: MiUser['id']; public userId: MiUser['id'];

View file

@ -12,6 +12,13 @@ export class MiPasswordResetRequest {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; 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 }) @Index({ unique: true })
@Column('varchar', { @Column('varchar', {
length: 256, length: 256,

View file

@ -14,6 +14,13 @@ export class MiPollVote {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the PollVote.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column(id()) @Column(id())
public userId: MiUser['id']; public userId: MiUser['id'];

View file

@ -14,6 +14,13 @@ export class MiPromoRead {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the PromoRead.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column(id()) @Column(id())
public userId: MiUser['id']; public userId: MiUser['id'];

View file

@ -12,6 +12,13 @@ export class MiRegistrationTicket {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; 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 }) @Index({ unique: true })
@Column('varchar', { @Column('varchar', {
length: 64, length: 64,

View file

@ -13,6 +13,13 @@ export class MiRegistryItem {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; 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', { @Column('timestamp with time zone', {
comment: 'The updated date of the RegistryItem.', comment: 'The updated date of the RegistryItem.',
}) })

View file

@ -13,6 +13,13 @@ export class MiRenoteMuting {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the RenoteMuting.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column({ @Column({
...id(), ...id(),

View file

@ -14,7 +14,8 @@ export class MiRetentionAggregation {
@Index() @Index()
@Column('timestamp with time zone', { @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; public createdAt: Date;

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-only * 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'; import { id } from './util/id.js';
type CondFormulaValueAnd = { type CondFormulaValueAnd = {
@ -89,6 +89,13 @@ export class MiRole {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; 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', { @Column('timestamp with time zone', {
comment: 'The updated date of the Role.', comment: 'The updated date of the Role.',
}) })

View file

@ -14,6 +14,13 @@ export class MiRoleAssignment {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the RoleAssignment.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column({ @Column({
...id(), ...id(),

View file

@ -12,6 +12,13 @@ export class MiSignin {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the Signin.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column(id()) @Column(id())
public userId: MiUser['id']; public userId: MiUser['id'];

View file

@ -12,6 +12,13 @@ export class MiSwSubscription {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the SwSubscriptipnpon.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column(id()) @Column(id())
public userId: MiUser['id']; public userId: MiUser['id'];

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
import { PrimaryColumn, Entity, Column } from 'typeorm'; import { PrimaryColumn, Entity, Column, Index } from 'typeorm';
@Entity('used_username') @Entity('used_username')
export class MiUsedUsername { export class MiUsedUsername {
@ -12,7 +12,11 @@ export class MiUsedUsername {
}) })
public username: string; 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; public createdAt: Date;
constructor(data: Partial<MiUsedUsername>) { constructor(data: Partial<MiUsedUsername>) {

View file

@ -13,6 +13,13 @@ export class MiUser {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the User.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column('timestamp with time zone', { @Column('timestamp with time zone', {
nullable: true, nullable: true,

View file

@ -13,7 +13,10 @@ export class MiUserIp {
@PrimaryGeneratedColumn() @PrimaryGeneratedColumn()
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', { @Column('timestamp with time zone', {
comment: 'The created date of the UserIp.',
default: () => 'CURRENT_TIMESTAMP',
}) })
public createdAt: Date; public createdAt: Date;

View file

@ -12,6 +12,13 @@ export class MiUserList {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the UserList.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column({ @Column({
...id(), ...id(),

View file

@ -14,6 +14,13 @@ export class MiUserListFavorite {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the UserListFavorite.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column(id()) @Column(id())
public userId: MiUser['id']; public userId: MiUser['id'];

View file

@ -14,6 +14,13 @@ export class MiUserListMembership {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the UserListMembership.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column({ @Column({
...id(), ...id(),

View file

@ -14,6 +14,13 @@ export class MiUserNotePining {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the UserNotePining.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column(id()) @Column(id())
public userId: MiUser['id']; public userId: MiUser['id'];

View file

@ -11,6 +11,13 @@ export class MiUserPending {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; 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 }) @Index({ unique: true })
@Column('varchar', { @Column('varchar', {
length: 128, length: 128,

View file

@ -14,6 +14,13 @@ export class MiWebhook {
@PrimaryColumn(id()) @PrimaryColumn(id())
public id: string; public id: string;
@Index()
@Column('timestamp with time zone', {
comment: 'The created date of the Webhook.',
default: () => 'CURRENT_TIMESTAMP',
})
public createdAt: Date;
@Index() @Index()
@Column({ @Column({
...id(), ...id(),

View file

@ -58,6 +58,10 @@ export const packedAnnouncementSchema = {
type: 'number', type: 'number',
optional: false, nullable: false, optional: false, nullable: false,
}, },
silence: {
type: 'boolean',
optional: false, nullable: false,
},
isRead: { isRead: {
type: 'boolean', type: 'boolean',
optional: true, nullable: false, optional: true, nullable: false,

View file

@ -69,6 +69,10 @@ export const meta = {
type: 'number', type: 'number',
optional: false, nullable: false, optional: false, nullable: false,
}, },
silence: {
type: 'boolean',
optional: false, nullable: false,
},
isRead: { isRead: {
type: 'boolean', type: 'boolean',
optional: true, nullable: false, optional: true, nullable: false,
@ -86,10 +90,10 @@ export const paramDef = {
icon: { type: 'string', enum: ['info', 'warning', 'error', 'success'], default: 'info' }, icon: { type: 'string', enum: ['info', 'warning', 'error', 'success'], default: 'info' },
display: { type: 'string', enum: ['normal', 'banner', 'dialog'], default: 'normal' }, display: { type: 'string', enum: ['normal', 'banner', 'dialog'], default: 'normal' },
forExistingUsers: { type: 'boolean', default: false }, forExistingUsers: { type: 'boolean', default: false },
silence: { type: 'boolean', default: false },
needConfirmationToRead: { type: 'boolean', default: false }, needConfirmationToRead: { type: 'boolean', default: false },
closeDuration: { type: 'number', default: 0 }, closeDuration: { type: 'number', default: 0 },
displayOrder: { type: 'number', default: 0 }, displayOrder: { type: 'number', default: 0 },
silence: { type: 'boolean', default: false },
userId: { type: 'string', format: 'misskey:id', nullable: true, default: null }, userId: { type: 'string', format: 'misskey:id', nullable: true, default: null },
}, },
required: ['title', 'text', 'imageUrl'], required: ['title', 'text', 'imageUrl'],
@ -109,10 +113,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
icon: ps.icon, icon: ps.icon,
display: ps.display, display: ps.display,
forExistingUsers: ps.forExistingUsers, forExistingUsers: ps.forExistingUsers,
silence: ps.silence,
needConfirmationToRead: ps.needConfirmationToRead, needConfirmationToRead: ps.needConfirmationToRead,
closeDuration: ps.closeDuration, closeDuration: ps.closeDuration,
displayOrder: ps.displayOrder, displayOrder: ps.displayOrder,
silence: ps.silence,
userId: ps.userId, userId: ps.userId,
}, me); }, me);

View file

@ -79,6 +79,10 @@ export const meta = {
type: 'number', type: 'number',
optional: false, nullable: false, optional: false, nullable: false,
}, },
silence: {
type: 'boolean',
optional: false, nullable: false,
},
userId: { userId: {
type: 'string', type: 'string',
optional: false, nullable: true, optional: false, nullable: true,
@ -128,13 +132,13 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
display: announcement.display, display: announcement.display,
isActive: announcement.isActive, isActive: announcement.isActive,
forExistingUsers: announcement.forExistingUsers, forExistingUsers: announcement.forExistingUsers,
silence: announcement.silence,
needConfirmationToRead: announcement.needConfirmationToRead, needConfirmationToRead: announcement.needConfirmationToRead,
closeDuration: announcement.closeDuration, closeDuration: announcement.closeDuration,
displayOrder: announcement.displayOrder, displayOrder: announcement.displayOrder,
silence: announcement.silence,
userId: announcement.userId, userId: announcement.userId,
user: announcement.userInfo, user: announcement.userInfo,
reads: announcement.readCount, reads: announcement.reads,
})); }));
}); });
} }

View file

@ -35,10 +35,10 @@ export const paramDef = {
icon: { type: 'string', enum: ['info', 'warning', 'error', 'success'] }, icon: { type: 'string', enum: ['info', 'warning', 'error', 'success'] },
display: { type: 'string', enum: ['normal', 'banner', 'dialog'] }, display: { type: 'string', enum: ['normal', 'banner', 'dialog'] },
forExistingUsers: { type: 'boolean' }, forExistingUsers: { type: 'boolean' },
silence: { type: 'boolean' },
needConfirmationToRead: { type: 'boolean' }, needConfirmationToRead: { type: 'boolean' },
closeDuration: { type: 'number', default: 0 }, closeDuration: { type: 'number', default: 0 },
displayOrder: { type: 'number', default: 0 }, displayOrder: { type: 'number', default: 0 },
silence: { type: 'boolean' },
isActive: { type: 'boolean' }, isActive: { type: 'boolean' },
}, },
required: ['id'], required: ['id'],
@ -66,10 +66,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
display: ps.display, display: ps.display,
icon: ps.icon, icon: ps.icon,
forExistingUsers: ps.forExistingUsers, forExistingUsers: ps.forExistingUsers,
silence: ps.silence,
needConfirmationToRead: ps.needConfirmationToRead, needConfirmationToRead: ps.needConfirmationToRead,
closeDuration: ps.closeDuration, closeDuration: ps.closeDuration,
displayOrder: ps.displayOrder, displayOrder: ps.displayOrder,
silence: ps.silence,
isActive: ps.isActive, isActive: ps.isActive,
}, me); }, me);
}); });

View file

@ -10,6 +10,7 @@ import { ModuleMocker } from 'jest-mock';
import { Test } from '@nestjs/testing'; import { Test } from '@nestjs/testing';
import { GlobalModule } from '@/GlobalModule.js'; import { GlobalModule } from '@/GlobalModule.js';
import { AnnouncementService } from '@/core/AnnouncementService.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 type { MiAnnouncement, AnnouncementsRepository, AnnouncementReadsRepository, UsersRepository, MiUser } from '@/models/_.js';
import { DI } from '@/di-symbols.js'; import { DI } from '@/di-symbols.js';
import { genAidx } from '@/misc/id/aidx.js'; import { genAidx } from '@/misc/id/aidx.js';
@ -61,6 +62,7 @@ describe('AnnouncementService', () => {
], ],
providers: [ providers: [
AnnouncementService, AnnouncementService,
AnnouncementEntityService,
CacheService, CacheService,
IdService, IdService,
], ],

View file

@ -49,7 +49,11 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkInput v-model="displayOrder" type="number"> <MkInput v-model="displayOrder" type="number">
<template #label>{{ i18n.ts.displayOrder }}</template> <template #label>{{ i18n.ts.displayOrder }}</template>
</MkInput> </MkInput>
<p v-if="readCount">{{ i18n.t('nUsersRead', { n: readCount }) }}</p> <MkSwitch v-model="silence">
{{ i18n.ts._announcement.silence }}
<template #caption>{{ i18n.ts._announcement.silenceDescription }}</template>
</MkSwitch>
<p v-if="reads">{{ i18n.t('nUsersRead', { n: reads }) }}</p>
<MkUserCardMini v-if="props.user.id" :user="props.user"></MkUserCardMini> <MkUserCardMini v-if="props.user.id" :user="props.user"></MkUserCardMini>
<MkButton v-if="announcement" danger @click="del()"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton> <MkButton v-if="announcement" danger @click="del()"><i class="ti ti-trash"></i> {{ i18n.ts.delete }}</MkButton>
</div> </div>
@ -62,7 +66,6 @@ SPDX-License-Identifier: AGPL-3.0-only
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import MkModalWindow from '@/components/MkModalWindow.vue'; import MkModalWindow from '@/components/MkModalWindow.vue';
import MkButton from '@/components/MkButton.vue'; import MkButton from '@/components/MkButton.vue';
@ -87,7 +90,8 @@ let display: string = $ref(props.announcement ? props.announcement.display : 'di
let needConfirmationToRead: boolean = $ref(props.announcement ? props.announcement.needConfirmationToRead : false); let needConfirmationToRead: boolean = $ref(props.announcement ? props.announcement.needConfirmationToRead : false);
let closeDuration: number = $ref(props.announcement ? props.announcement.closeDuration : 0); let closeDuration: number = $ref(props.announcement ? props.announcement.closeDuration : 0);
let displayOrder: number = $ref(props.announcement ? props.announcement.displayOrder : 0); let displayOrder: number = $ref(props.announcement ? props.announcement.displayOrder : 0);
let readCount: number = $ref(props.announcement ? props.announcement.readCount : 0); let silence: boolean = $ref(props.announcement ? props.announcement.silence : false);
let reads: number = $ref(props.announcement ? props.announcement.reads : 0);
const emit = defineEmits<{ const emit = defineEmits<{
(ev: 'done', v: { deleted?: boolean; updated?: any; created?: any }): void, (ev: 'done', v: { deleted?: boolean; updated?: any; created?: any }): void,
@ -110,7 +114,8 @@ async function done(): Promise<void> {
needConfirmationToRead: needConfirmationToRead, needConfirmationToRead: needConfirmationToRead,
closeDuration: closeDuration, closeDuration: closeDuration,
displayOrder: displayOrder, displayOrder: displayOrder,
readCount: readCount, silence: silence,
reads: reads,
userId: props.user.id, userId: props.user.id,
}; };

View file

@ -63,9 +63,6 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSwitch v-model="announcement.forExistingUsers" :helpText="i18n.ts._announcement.forExistingUsersDescription"> <MkSwitch v-model="announcement.forExistingUsers" :helpText="i18n.ts._announcement.forExistingUsersDescription">
{{ i18n.ts._announcement.forExistingUsers }} {{ i18n.ts._announcement.forExistingUsers }}
</MkSwitch> </MkSwitch>
<MkSwitch v-model="announcement.silence" :helpText="i18n.ts._announcement.silenceDescription">
{{ i18n.ts._announcement.silence }}
</MkSwitch>
<MkSwitch v-model="announcement.needConfirmationToRead" :helpText="i18n.ts._announcement.needConfirmationToReadDescription"> <MkSwitch v-model="announcement.needConfirmationToRead" :helpText="i18n.ts._announcement.needConfirmationToReadDescription">
{{ i18n.ts._announcement.needConfirmationToRead }} {{ i18n.ts._announcement.needConfirmationToRead }}
</MkSwitch> </MkSwitch>
@ -76,6 +73,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkInput v-model="announcement.displayOrder" type="number"> <MkInput v-model="announcement.displayOrder" type="number">
<template #label>{{ i18n.ts.displayOrder }}</template> <template #label>{{ i18n.ts.displayOrder }}</template>
</MkInput> </MkInput>
<MkSwitch v-model="announcement.silence" :helpText="i18n.ts._announcement.silenceDescription">
{{ i18n.ts._announcement.silence }}
</MkSwitch>
<p v-if="announcement.reads">{{ i18n.t('nUsersRead', { n: announcement.reads }) }}</p> <p v-if="announcement.reads">{{ i18n.t('nUsersRead', { n: announcement.reads }) }}</p>
<MkUserCardMini v-if="announcement.userId" :user="announcement.user" @click="editUser(announcement)"></MkUserCardMini> <MkUserCardMini v-if="announcement.userId" :user="announcement.user" @click="editUser(announcement)"></MkUserCardMini>
<MkButton v-else class="button" inline primary @click="editUser(announcement)">{{ i18n.ts.specifyUser }}</MkButton> <MkButton v-else class="button" inline primary @click="editUser(announcement)">{{ i18n.ts.specifyUser }}</MkButton>
@ -144,10 +144,10 @@ function add() {
icon: 'info', icon: 'info',
display: 'normal', display: 'normal',
forExistingUsers: false, forExistingUsers: false,
silence: false,
needConfirmationToRead: false, needConfirmationToRead: false,
closeDuration: 0, closeDuration: 0,
displayOrder: 0, displayOrder: 0,
silence: false,
}); });
} }

View file

@ -49,6 +49,7 @@ type Announcement = {
needConfirmationToRead: boolean; needConfirmationToRead: boolean;
closeDuration: number; closeDuration: number;
displayOrder: number; displayOrder: number;
silence: boolean;
forYou: boolean; forYou: boolean;
isRead?: boolean; isRead?: boolean;
}; };
@ -3073,7 +3074,7 @@ type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+u
// src/api.types.ts:20:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts // src/api.types.ts:20:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts
// src/api.types.ts:638:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts // src/api.types.ts:638:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts
// src/entities.ts:119:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts // src/entities.ts:119:2 - (ae-forgotten-export) The symbol "notificationTypes_2" needs to be exported by the entry point index.d.ts
// src/entities.ts:636:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts // src/entities.ts:637:2 - (ae-forgotten-export) The symbol "ModerationLogPayloads" needs to be exported by the entry point index.d.ts
// src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts // src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts
// (No @packageDocumentation comment for this package) // (No @packageDocumentation comment for this package)

View file

@ -476,6 +476,7 @@ export type Announcement = {
needConfirmationToRead: boolean; needConfirmationToRead: boolean;
closeDuration: number; closeDuration: number;
displayOrder: number; displayOrder: number;
silence: boolean;
forYou: boolean; forYou: boolean;
isRead?: boolean; isRead?: boolean;
}; };