refactor (backend): convert jsonb to array
This commit is contained in:
parent
3d28acb2c9
commit
a4779f233b
21 changed files with 394 additions and 143 deletions
|
@ -1,6 +1,9 @@
|
||||||
BEGIN;
|
BEGIN;
|
||||||
|
|
||||||
DELETE FROM "migrations" WHERE name IN (
|
DELETE FROM "migrations" WHERE name IN (
|
||||||
|
'UserprofileJsonbToArray1714270605574',
|
||||||
|
'DropUnusedUserprofileColumns1714259023878',
|
||||||
|
'AntennaJsonbToArray1714192520471',
|
||||||
'AddUserProfileLanguage1714888400293',
|
'AddUserProfileLanguage1714888400293',
|
||||||
'DropUnusedIndexes1714643926317',
|
'DropUnusedIndexes1714643926317',
|
||||||
'AlterAkaType1714099399879',
|
'AlterAkaType1714099399879',
|
||||||
|
@ -27,6 +30,45 @@ DELETE FROM "migrations" WHERE name IN (
|
||||||
'RemoveNativeUtilsMigration1705877093218'
|
'RemoveNativeUtilsMigration1705877093218'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- userprofile-jsonb-to-array
|
||||||
|
ALTER TABLE "user_profile" RENAME COLUMN "mutedInstances" TO "mutedInstances_old";
|
||||||
|
ALTER TABLE "user_profile" ADD COLUMN "mutedInstances" jsonb NOT NULL DEFAULT '[]';
|
||||||
|
UPDATE "user_profile" SET "mutedInstances" = to_jsonb("mutedInstances_old");
|
||||||
|
ALTER TABLE "user_profile" DROP COLUMN "mutedInstances_old";
|
||||||
|
ALTER TABLE "user_profile" RENAME COLUMN "mutedWords" TO "mutedWords_old";
|
||||||
|
ALTER TABLE "user_profile" ADD COLUMN "mutedWords" jsonb NOT NULL DEFAULT '[]';
|
||||||
|
CREATE TEMP TABLE "BCrsGgLCUeMMLARy" ("userId" character varying(32), "kws" jsonb NOT NULL DEFAULT '[]');
|
||||||
|
INSERT INTO "BCrsGgLCUeMMLARy" ("userId", "kws") SELECT "userId", jsonb_agg("X"."w") FROM (SELECT "userId", to_jsonb(string_to_array(unnest("mutedWords_old"), ' ')) AS "w" FROM "user_profile") AS "X" GROUP BY "userId";
|
||||||
|
UPDATE "user_profile" SET "mutedWords" = "kws" FROM "BCrsGgLCUeMMLARy" WHERE "user_profile"."userId" = "BCrsGgLCUeMMLARy"."userId";
|
||||||
|
ALTER TABLE "user_profile" DROP COLUMN "mutedWords_old";
|
||||||
|
|
||||||
|
-- drop-unused-userprofile-columns
|
||||||
|
ALTER TABLE "user_profile" ADD "room" jsonb NOT NULL DEFAULT '{}';
|
||||||
|
COMMENT ON COLUMN "user_profile"."room" IS 'The room data of the User.';
|
||||||
|
ALTER TABLE "user_profile" ADD "clientData" jsonb NOT NULL DEFAULT '{}';
|
||||||
|
COMMENT ON COLUMN "user_profile"."clientData" IS 'The client-specific data of the User.';
|
||||||
|
|
||||||
|
-- antenna-jsonb-to-array
|
||||||
|
UPDATE "antenna" SET "instances" = '{""}' WHERE "instances" = '{}';
|
||||||
|
ALTER TABLE "antenna" RENAME COLUMN "instances" TO "instances_old";
|
||||||
|
ALTER TABLE "antenna" ADD COLUMN "instances" jsonb NOT NULL DEFAULT '[]';
|
||||||
|
UPDATE "antenna" SET "instances" = to_jsonb("instances_old");
|
||||||
|
ALTER TABLE "antenna" DROP COLUMN "instances_old";
|
||||||
|
UPDATE "antenna" SET "keywords" = '{""}' WHERE "keywords" = '{}';
|
||||||
|
ALTER TABLE "antenna" RENAME COLUMN "keywords" TO "keywords_old";
|
||||||
|
ALTER TABLE "antenna" ADD COLUMN "keywords" jsonb NOT NULL DEFAULT '[]';
|
||||||
|
CREATE TEMP TABLE "QvPNcMitBFkqqBgm" ("id" character varying(32), "kws" jsonb NOT NULL DEFAULT '[]');
|
||||||
|
INSERT INTO "QvPNcMitBFkqqBgm" ("id", "kws") SELECT "id", jsonb_agg("X"."w") FROM (SELECT "id", to_jsonb(string_to_array(unnest("keywords_old"), ' ')) AS "w" FROM "antenna") AS "X" GROUP BY "id";
|
||||||
|
UPDATE "antenna" SET "keywords" = "kws" FROM "QvPNcMitBFkqqBgm" WHERE "antenna"."id" = "QvPNcMitBFkqqBgm"."id";
|
||||||
|
ALTER TABLE "antenna" DROP COLUMN "keywords_old";
|
||||||
|
UPDATE "antenna" SET "excludeKeywords" = '{""}' WHERE "excludeKeywords" = '{}';
|
||||||
|
ALTER TABLE "antenna" RENAME COLUMN "excludeKeywords" TO "excludeKeywords_old";
|
||||||
|
ALTER TABLE "antenna" ADD COLUMN "excludeKeywords" jsonb NOT NULL DEFAULT '[]';
|
||||||
|
CREATE TEMP TABLE "MZvVSjHzYcGXmGmz" ("id" character varying(32), "kws" jsonb NOT NULL DEFAULT '[]');
|
||||||
|
INSERT INTO "MZvVSjHzYcGXmGmz" ("id", "kws") SELECT "id", jsonb_agg("X"."w") FROM (SELECT "id", to_jsonb(string_to_array(unnest("excludeKeywords_old"), ' ')) AS "w" FROM "antenna") AS "X" GROUP BY "id";
|
||||||
|
UPDATE "antenna" SET "excludeKeywords" = "kws" FROM "MZvVSjHzYcGXmGmz" WHERE "antenna"."id" = "MZvVSjHzYcGXmGmz"."id";
|
||||||
|
ALTER TABLE "antenna" DROP COLUMN "excludeKeywords_old";
|
||||||
|
|
||||||
-- drop-unused-indexes
|
-- drop-unused-indexes
|
||||||
CREATE INDEX "IDX_01f4581f114e0ebd2bbb876f0b" ON "note_reaction" ("createdAt");
|
CREATE INDEX "IDX_01f4581f114e0ebd2bbb876f0b" ON "note_reaction" ("createdAt");
|
||||||
CREATE INDEX "IDX_0610ebcfcfb4a18441a9bcdab2" ON "poll" ("userId");
|
CREATE INDEX "IDX_0610ebcfcfb4a18441a9bcdab2" ON "poll" ("userId");
|
||||||
|
|
14
packages/backend-rs/index.d.ts
vendored
14
packages/backend-rs/index.d.ts
vendored
|
@ -244,7 +244,7 @@ export interface NoteLikeForCheckWordMute {
|
||||||
renoteId: string | null
|
renoteId: string | null
|
||||||
replyId: string | null
|
replyId: string | null
|
||||||
}
|
}
|
||||||
export function checkWordMute(note: NoteLikeForCheckWordMute, mutedWordLists: Array<Array<string>>, mutedPatterns: Array<string>): Promise<boolean>
|
export function checkWordMute(note: NoteLikeForCheckWordMute, mutedWords: Array<string>, mutedPatterns: Array<string>): Promise<boolean>
|
||||||
export function getFullApAccount(username: string, host?: string | undefined | null): string
|
export function getFullApAccount(username: string, host?: string | undefined | null): string
|
||||||
export function isSelfHost(host?: string | undefined | null): boolean
|
export function isSelfHost(host?: string | undefined | null): boolean
|
||||||
export function isSameOrigin(uri: string): boolean
|
export function isSameOrigin(uri: string): boolean
|
||||||
|
@ -381,7 +381,6 @@ export interface Antenna {
|
||||||
name: string
|
name: string
|
||||||
src: AntennaSrcEnum
|
src: AntennaSrcEnum
|
||||||
userListId: string | null
|
userListId: string | null
|
||||||
keywords: Json
|
|
||||||
withFile: boolean
|
withFile: boolean
|
||||||
expression: string | null
|
expression: string | null
|
||||||
notify: boolean
|
notify: boolean
|
||||||
|
@ -389,8 +388,9 @@ export interface Antenna {
|
||||||
withReplies: boolean
|
withReplies: boolean
|
||||||
userGroupJoiningId: string | null
|
userGroupJoiningId: string | null
|
||||||
users: Array<string>
|
users: Array<string>
|
||||||
excludeKeywords: Json
|
instances: Array<string>
|
||||||
instances: Json
|
keywords: Array<string>
|
||||||
|
excludeKeywords: Array<string>
|
||||||
}
|
}
|
||||||
export interface App {
|
export interface App {
|
||||||
id: string
|
id: string
|
||||||
|
@ -1128,7 +1128,6 @@ export interface UserProfile {
|
||||||
twoFactorSecret: string | null
|
twoFactorSecret: string | null
|
||||||
twoFactorEnabled: boolean
|
twoFactorEnabled: boolean
|
||||||
password: string | null
|
password: string | null
|
||||||
clientData: Json
|
|
||||||
autoAcceptFollowed: boolean
|
autoAcceptFollowed: boolean
|
||||||
alwaysMarkNsfw: boolean
|
alwaysMarkNsfw: boolean
|
||||||
carefulBot: boolean
|
carefulBot: boolean
|
||||||
|
@ -1136,21 +1135,20 @@ export interface UserProfile {
|
||||||
securityKeysAvailable: boolean
|
securityKeysAvailable: boolean
|
||||||
usePasswordLessLogin: boolean
|
usePasswordLessLogin: boolean
|
||||||
pinnedPageId: string | null
|
pinnedPageId: string | null
|
||||||
room: Json
|
|
||||||
injectFeaturedNote: boolean
|
injectFeaturedNote: boolean
|
||||||
enableWordMute: boolean
|
enableWordMute: boolean
|
||||||
mutedWords: Json
|
|
||||||
mutingNotificationTypes: Array<UserProfileMutingnotificationtypesEnum>
|
mutingNotificationTypes: Array<UserProfileMutingnotificationtypesEnum>
|
||||||
noCrawle: boolean
|
noCrawle: boolean
|
||||||
receiveAnnouncementEmail: boolean
|
receiveAnnouncementEmail: boolean
|
||||||
emailNotificationTypes: Json
|
emailNotificationTypes: Json
|
||||||
mutedInstances: Json
|
|
||||||
publicReactions: boolean
|
publicReactions: boolean
|
||||||
ffVisibility: UserProfileFfvisibilityEnum
|
ffVisibility: UserProfileFfvisibilityEnum
|
||||||
moderationNote: string
|
moderationNote: string
|
||||||
preventAiLearning: boolean
|
preventAiLearning: boolean
|
||||||
isIndexable: boolean
|
isIndexable: boolean
|
||||||
mutedPatterns: Array<string>
|
mutedPatterns: Array<string>
|
||||||
|
mutedInstances: Array<string>
|
||||||
|
mutedWords: Array<string>
|
||||||
lang: string | null
|
lang: string | null
|
||||||
}
|
}
|
||||||
export interface UserPublickey {
|
export interface UserPublickey {
|
||||||
|
|
|
@ -87,14 +87,13 @@ fn convert_regex(js_regex: &str) -> String {
|
||||||
|
|
||||||
fn check_word_mute_impl(
|
fn check_word_mute_impl(
|
||||||
texts: &[String],
|
texts: &[String],
|
||||||
muted_word_lists: &[Vec<String>],
|
muted_words: &[String],
|
||||||
muted_patterns: &[String],
|
muted_patterns: &[String],
|
||||||
) -> bool {
|
) -> bool {
|
||||||
muted_word_lists.iter().any(|muted_word_list| {
|
muted_words.iter().any(|item| {
|
||||||
texts.iter().any(|text| {
|
texts.iter().any(|text| {
|
||||||
let text_lower = text.to_lowercase();
|
let text_lower = text.to_lowercase();
|
||||||
muted_word_list
|
item.split_whitespace()
|
||||||
.iter()
|
|
||||||
.all(|muted_word| text_lower.contains(&muted_word.to_lowercase()))
|
.all(|muted_word| text_lower.contains(&muted_word.to_lowercase()))
|
||||||
})
|
})
|
||||||
}) || muted_patterns.iter().any(|muted_pattern| {
|
}) || muted_patterns.iter().any(|muted_pattern| {
|
||||||
|
@ -107,16 +106,16 @@ fn check_word_mute_impl(
|
||||||
#[crate::export]
|
#[crate::export]
|
||||||
pub async fn check_word_mute(
|
pub async fn check_word_mute(
|
||||||
note: NoteLike,
|
note: NoteLike,
|
||||||
muted_word_lists: Vec<Vec<String>>,
|
muted_words: &[String],
|
||||||
muted_patterns: Vec<String>,
|
muted_patterns: &[String],
|
||||||
) -> Result<bool, DbErr> {
|
) -> Result<bool, DbErr> {
|
||||||
if muted_word_lists.is_empty() && muted_patterns.is_empty() {
|
if muted_words.is_empty() && muted_patterns.is_empty() {
|
||||||
Ok(false)
|
Ok(false)
|
||||||
} else {
|
} else {
|
||||||
Ok(check_word_mute_impl(
|
Ok(check_word_mute_impl(
|
||||||
&all_texts(note).await?,
|
&all_texts(note).await?,
|
||||||
&muted_word_lists,
|
muted_words,
|
||||||
&muted_patterns,
|
muted_patterns,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,6 @@ pub struct Model {
|
||||||
pub src: AntennaSrcEnum,
|
pub src: AntennaSrcEnum,
|
||||||
#[sea_orm(column_name = "userListId")]
|
#[sea_orm(column_name = "userListId")]
|
||||||
pub user_list_id: Option<String>,
|
pub user_list_id: Option<String>,
|
||||||
#[sea_orm(column_type = "JsonBinary")]
|
|
||||||
pub keywords: Json,
|
|
||||||
#[sea_orm(column_name = "withFile")]
|
#[sea_orm(column_name = "withFile")]
|
||||||
pub with_file: bool,
|
pub with_file: bool,
|
||||||
pub expression: Option<String>,
|
pub expression: Option<String>,
|
||||||
|
@ -34,10 +32,10 @@ pub struct Model {
|
||||||
#[sea_orm(column_name = "userGroupJoiningId")]
|
#[sea_orm(column_name = "userGroupJoiningId")]
|
||||||
pub user_group_joining_id: Option<String>,
|
pub user_group_joining_id: Option<String>,
|
||||||
pub users: Vec<String>,
|
pub users: Vec<String>,
|
||||||
#[sea_orm(column_name = "excludeKeywords", column_type = "JsonBinary")]
|
pub instances: Vec<String>,
|
||||||
pub exclude_keywords: Json,
|
pub keywords: Vec<String>,
|
||||||
#[sea_orm(column_type = "JsonBinary")]
|
#[sea_orm(column_name = "excludeKeywords")]
|
||||||
pub instances: Json,
|
pub exclude_keywords: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
|
|
@ -32,8 +32,6 @@ pub struct Model {
|
||||||
#[sea_orm(column_name = "twoFactorEnabled")]
|
#[sea_orm(column_name = "twoFactorEnabled")]
|
||||||
pub two_factor_enabled: bool,
|
pub two_factor_enabled: bool,
|
||||||
pub password: Option<String>,
|
pub password: Option<String>,
|
||||||
#[sea_orm(column_name = "clientData", column_type = "JsonBinary")]
|
|
||||||
pub client_data: Json,
|
|
||||||
#[sea_orm(column_name = "autoAcceptFollowed")]
|
#[sea_orm(column_name = "autoAcceptFollowed")]
|
||||||
pub auto_accept_followed: bool,
|
pub auto_accept_followed: bool,
|
||||||
#[sea_orm(column_name = "alwaysMarkNsfw")]
|
#[sea_orm(column_name = "alwaysMarkNsfw")]
|
||||||
|
@ -48,14 +46,10 @@ pub struct Model {
|
||||||
pub use_password_less_login: bool,
|
pub use_password_less_login: bool,
|
||||||
#[sea_orm(column_name = "pinnedPageId", unique)]
|
#[sea_orm(column_name = "pinnedPageId", unique)]
|
||||||
pub pinned_page_id: Option<String>,
|
pub pinned_page_id: Option<String>,
|
||||||
#[sea_orm(column_type = "JsonBinary")]
|
|
||||||
pub room: Json,
|
|
||||||
#[sea_orm(column_name = "injectFeaturedNote")]
|
#[sea_orm(column_name = "injectFeaturedNote")]
|
||||||
pub inject_featured_note: bool,
|
pub inject_featured_note: bool,
|
||||||
#[sea_orm(column_name = "enableWordMute")]
|
#[sea_orm(column_name = "enableWordMute")]
|
||||||
pub enable_word_mute: bool,
|
pub enable_word_mute: bool,
|
||||||
#[sea_orm(column_name = "mutedWords", column_type = "JsonBinary")]
|
|
||||||
pub muted_words: Json,
|
|
||||||
#[sea_orm(column_name = "mutingNotificationTypes")]
|
#[sea_orm(column_name = "mutingNotificationTypes")]
|
||||||
pub muting_notification_types: Vec<UserProfileMutingnotificationtypesEnum>,
|
pub muting_notification_types: Vec<UserProfileMutingnotificationtypesEnum>,
|
||||||
#[sea_orm(column_name = "noCrawle")]
|
#[sea_orm(column_name = "noCrawle")]
|
||||||
|
@ -64,8 +58,6 @@ pub struct Model {
|
||||||
pub receive_announcement_email: bool,
|
pub receive_announcement_email: bool,
|
||||||
#[sea_orm(column_name = "emailNotificationTypes", column_type = "JsonBinary")]
|
#[sea_orm(column_name = "emailNotificationTypes", column_type = "JsonBinary")]
|
||||||
pub email_notification_types: Json,
|
pub email_notification_types: Json,
|
||||||
#[sea_orm(column_name = "mutedInstances", column_type = "JsonBinary")]
|
|
||||||
pub muted_instances: Json,
|
|
||||||
#[sea_orm(column_name = "publicReactions")]
|
#[sea_orm(column_name = "publicReactions")]
|
||||||
pub public_reactions: bool,
|
pub public_reactions: bool,
|
||||||
#[sea_orm(column_name = "ffVisibility")]
|
#[sea_orm(column_name = "ffVisibility")]
|
||||||
|
@ -78,6 +70,10 @@ pub struct Model {
|
||||||
pub is_indexable: bool,
|
pub is_indexable: bool,
|
||||||
#[sea_orm(column_name = "mutedPatterns")]
|
#[sea_orm(column_name = "mutedPatterns")]
|
||||||
pub muted_patterns: Vec<String>,
|
pub muted_patterns: Vec<String>,
|
||||||
|
#[sea_orm(column_name = "mutedInstances")]
|
||||||
|
pub muted_instances: Vec<String>,
|
||||||
|
#[sea_orm(column_name = "mutedWords")]
|
||||||
|
pub muted_words: Vec<String>,
|
||||||
pub lang: Option<String>,
|
pub lang: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
import type { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class AntennaJsonbToArray1714192520471 implements MigrationInterface {
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "antenna" RENAME COLUMN "instances" TO "instances_old"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "antenna" ADD COLUMN "instances" character varying(512)[] NOT NULL DEFAULT '{}'`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`UPDATE "antenna" SET "instances" = ARRAY(SELECT jsonb_array_elements_text("instances_old"))::character varying(512)[]`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`UPDATE "antenna" SET "instances" = '{}' WHERE "instances" = '{""}'`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "antenna" DROP COLUMN "instances_old"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "antenna" RENAME COLUMN "keywords" TO "keywords_old"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "antenna" ADD COLUMN "keywords" text[] NOT NULL DEFAULT '{}'`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE TEMP TABLE "HMyeXPcdtQYGsSrf" ("id" character varying(32), "kws" text[])`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`INSERT INTO "HMyeXPcdtQYGsSrf" ("id", "kws") SELECT "id", array_agg("X"."w") FROM (SELECT "id", array_to_string(ARRAY(SELECT jsonb_array_elements_text("kw")), ' ') AS "w" FROM (SELECT "id", jsonb_array_elements("keywords_old") AS "kw" FROM "antenna") AS "a") AS "X" GROUP BY "id"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`UPDATE "antenna" SET "keywords" = "kws" FROM "HMyeXPcdtQYGsSrf" WHERE "antenna"."id" = "HMyeXPcdtQYGsSrf"."id"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`UPDATE "antenna" SET "keywords" = '{}' WHERE "keywords" = '{""}'`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "keywords_old"`);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "antenna" RENAME COLUMN "excludeKeywords" TO "excludeKeywords_old"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "antenna" ADD COLUMN "excludeKeywords" text[] NOT NULL DEFAULT '{}'`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE TEMP TABLE "kpdsACdZTRYqLkfK" ("id" character varying(32), "kws" text[])`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`INSERT INTO "kpdsACdZTRYqLkfK" ("id", "kws") SELECT "id", array_agg("X"."w") FROM (SELECT "id", array_to_string(ARRAY(SELECT jsonb_array_elements_text("kw")), ' ') AS "w" FROM (SELECT "id", jsonb_array_elements("excludeKeywords_old") AS "kw" FROM "antenna") AS "a") AS "X" GROUP BY "id"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`UPDATE "antenna" SET "excludeKeywords" = "kws" FROM "kpdsACdZTRYqLkfK" WHERE "antenna"."id" = "kpdsACdZTRYqLkfK"."id"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`UPDATE "antenna" SET "excludeKeywords" = '{}' WHERE "excludeKeywords" = '{""}'`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "antenna" DROP COLUMN "excludeKeywords_old"`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`UPDATE "antenna" SET "instances" = '{""}' WHERE "instances" = '{}'`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "antenna" RENAME COLUMN "instances" TO "instances_old"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "antenna" ADD COLUMN "instances" jsonb NOT NULL DEFAULT '[]'`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`UPDATE "antenna" SET "instances" = to_jsonb("instances_old")`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "antenna" DROP COLUMN "instances_old"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`UPDATE "antenna" SET "keywords" = '{""}' WHERE "keywords" = '{}'`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "antenna" RENAME COLUMN "keywords" TO "keywords_old"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "antenna" ADD COLUMN "keywords" jsonb NOT NULL DEFAULT '[]'`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE TEMP TABLE "QvPNcMitBFkqqBgm" ("id" character varying(32), "kws" jsonb NOT NULL DEFAULT '[]')`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`INSERT INTO "QvPNcMitBFkqqBgm" ("id", "kws") SELECT "id", jsonb_agg("X"."w") FROM (SELECT "id", to_jsonb(string_to_array(unnest("keywords_old"), ' ')) AS "w" FROM "antenna") AS "X" GROUP BY "id"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`UPDATE "antenna" SET "keywords" = "kws" FROM "QvPNcMitBFkqqBgm" WHERE "antenna"."id" = "QvPNcMitBFkqqBgm"."id"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "keywords_old"`);
|
||||||
|
await queryRunner.query(
|
||||||
|
`UPDATE "antenna" SET "excludeKeywords" = '{""}' WHERE "excludeKeywords" = '{}'`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "antenna" RENAME COLUMN "excludeKeywords" TO "excludeKeywords_old"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "antenna" ADD COLUMN "excludeKeywords" jsonb NOT NULL DEFAULT '[]'`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE TEMP TABLE "MZvVSjHzYcGXmGmz" ("id" character varying(32), "kws" jsonb NOT NULL DEFAULT '[]')`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`INSERT INTO "MZvVSjHzYcGXmGmz" ("id", "kws") SELECT "id", jsonb_agg("X"."w") FROM (SELECT "id", to_jsonb(string_to_array(unnest("excludeKeywords_old"), ' ')) AS "w" FROM "antenna") AS "X" GROUP BY "id"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`UPDATE "antenna" SET "excludeKeywords" = "kws" FROM "MZvVSjHzYcGXmGmz" WHERE "antenna"."id" = "MZvVSjHzYcGXmGmz"."id"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "antenna" DROP COLUMN "excludeKeywords_old"`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
import type { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class DropUnusedUserprofileColumns1714259023878
|
||||||
|
implements MigrationInterface
|
||||||
|
{
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user_profile" DROP COLUMN "clientData"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "room"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user_profile" ADD "room" jsonb NOT NULL DEFAULT '{}'`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`COMMENT ON COLUMN "user_profile"."room" IS 'The room data of the User.'`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user_profile" ADD "clientData" jsonb NOT NULL DEFAULT '{}'`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`COMMENT ON COLUMN "user_profile"."clientData" IS 'The client-specific data of the User.'`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
import type { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class UserprofileJsonbToArray1714270605574
|
||||||
|
implements MigrationInterface
|
||||||
|
{
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user_profile" RENAME COLUMN "mutedInstances" TO "mutedInstances_old"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user_profile" ADD COLUMN "mutedInstances" character varying(512)[] NOT NULL DEFAULT '{}'`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`UPDATE "user_profile" SET "mutedInstances" = ARRAY(SELECT jsonb_array_elements_text("mutedInstances_old"))::character varying(512)[]`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user_profile" DROP COLUMN "mutedInstances_old"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user_profile" RENAME COLUMN "mutedWords" TO "mutedWords_old"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user_profile" ADD COLUMN "mutedWords" text[] NOT NULL DEFAULT '{}'`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE TEMP TABLE "MmVqAUUgpshTCQcw" ("userId" character varying(32), "kws" text[])`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`INSERT INTO "MmVqAUUgpshTCQcw" ("userId", "kws") SELECT "userId", array_agg("X"."w") FROM (SELECT "userId", array_to_string(ARRAY(SELECT jsonb_array_elements_text("kw")), ' ') AS "w" FROM (SELECT "userId", jsonb_array_elements("mutedWords_old") AS "kw" FROM "user_profile") AS "a") AS "X" GROUP BY "userId"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`UPDATE "user_profile" SET "mutedWords" = "kws" FROM "MmVqAUUgpshTCQcw" WHERE "user_profile"."userId" = "MmVqAUUgpshTCQcw"."userId"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user_profile" DROP COLUMN "mutedWords_old"`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user_profile" RENAME COLUMN "mutedInstances" TO "mutedInstances_old"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user_profile" ADD COLUMN "mutedInstances" jsonb NOT NULL DEFAULT '[]'`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`UPDATE "user_profile" SET "mutedInstances" = to_jsonb("mutedInstances_old")`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user_profile" DROP COLUMN "mutedInstances_old"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user_profile" RENAME COLUMN "mutedWords" TO "mutedWords_old"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user_profile" ADD COLUMN "mutedWords" jsonb NOT NULL DEFAULT '[]'`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE TEMP TABLE "BCrsGgLCUeMMLARy" ("userId" character varying(32), "kws" jsonb NOT NULL DEFAULT '[]')`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`INSERT INTO "BCrsGgLCUeMMLARy" ("userId", "kws") SELECT "userId", jsonb_agg("X"."w") FROM (SELECT "userId", to_jsonb(string_to_array(unnest("mutedWords_old"), ' ')) AS "w" FROM "user_profile") AS "X" GROUP BY "userId"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`UPDATE "user_profile" SET "mutedWords" = "kws" FROM "BCrsGgLCUeMMLARy" WHERE "user_profile"."userId" = "BCrsGgLCUeMMLARy"."userId"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "user_profile" DROP COLUMN "mutedWords_old"`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -46,44 +46,38 @@ export async function checkHitAntenna(
|
||||||
if (!instances.includes(noteUser.host?.toLowerCase() ?? "")) return false;
|
if (!instances.includes(noteUser.host?.toLowerCase() ?? "")) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const keywords = antenna.keywords
|
|
||||||
// Clean up
|
|
||||||
.map((xs) => xs.filter((x) => x !== ""))
|
|
||||||
.filter((xs) => xs.length > 0);
|
|
||||||
|
|
||||||
let text = `${note.text ?? ""} ${note.cw ?? ""}`;
|
let text = `${note.text ?? ""} ${note.cw ?? ""}`;
|
||||||
if (note.files != null)
|
if (note.files != null)
|
||||||
text += ` ${note.files.map((f) => f.comment ?? "").join(" ")}`;
|
text += ` ${note.files.map((f) => f.comment ?? "").join(" ")}`;
|
||||||
text = text.trim();
|
text = text.trim();
|
||||||
|
|
||||||
if (keywords.length > 0) {
|
if (antenna.keywords.length > 0) {
|
||||||
if (note.text == null) return false;
|
if (note.text == null) return false;
|
||||||
|
|
||||||
const matched = keywords.some((and) =>
|
const matched = antenna.keywords.some((item) =>
|
||||||
and.every((keyword) =>
|
item
|
||||||
antenna.caseSensitive
|
.split(" ")
|
||||||
? text.includes(keyword)
|
.every((keyword) =>
|
||||||
: text.toLowerCase().includes(keyword.toLowerCase()),
|
antenna.caseSensitive
|
||||||
),
|
? text.includes(keyword)
|
||||||
|
: text.toLowerCase().includes(keyword.toLowerCase()),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!matched) return false;
|
if (!matched) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const excludeKeywords = antenna.excludeKeywords
|
if (antenna.excludeKeywords.length > 0) {
|
||||||
// Clean up
|
|
||||||
.map((xs) => xs.filter((x) => x !== ""))
|
|
||||||
.filter((xs) => xs.length > 0);
|
|
||||||
|
|
||||||
if (excludeKeywords.length > 0) {
|
|
||||||
if (note.text == null) return false;
|
if (note.text == null) return false;
|
||||||
|
|
||||||
const matched = excludeKeywords.some((and) =>
|
const matched = antenna.excludeKeywords.some((item) =>
|
||||||
and.every((keyword) =>
|
item
|
||||||
antenna.caseSensitive
|
.split(" ")
|
||||||
? note.text?.includes(keyword)
|
.every((keyword) =>
|
||||||
: note.text?.toLowerCase().includes(keyword.toLowerCase()),
|
antenna.caseSensitive
|
||||||
),
|
? note.text?.includes(keyword)
|
||||||
|
: note.text?.toLowerCase().includes(keyword.toLowerCase()),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (matched) return false;
|
if (matched) return false;
|
||||||
|
|
|
@ -59,20 +59,30 @@ export class Antenna {
|
||||||
})
|
})
|
||||||
public users: string[];
|
public users: string[];
|
||||||
|
|
||||||
@Column("jsonb", {
|
@Column("varchar", {
|
||||||
default: [],
|
length: 512,
|
||||||
|
array: true,
|
||||||
|
default: "{}",
|
||||||
})
|
})
|
||||||
public instances: string[];
|
public instances: string[];
|
||||||
|
|
||||||
@Column("jsonb", {
|
// whitespace: AND condition
|
||||||
default: [],
|
// array items: OR condition
|
||||||
|
// e.g., ["alpha beta", "gamma"]
|
||||||
|
// does match "alpha beta", "beta alpha alpha", "gamma alpha", "gamma epsilon"
|
||||||
|
// does not match "alpha", "beta gamma", "alpha alpha", "eplison"
|
||||||
|
@Column("text", {
|
||||||
|
array: true,
|
||||||
|
default: "{}",
|
||||||
})
|
})
|
||||||
public keywords: string[][];
|
public keywords: string[];
|
||||||
|
|
||||||
@Column("jsonb", {
|
// same match rule as `keywords`, except that this field is for excluded words
|
||||||
default: [],
|
@Column("text", {
|
||||||
|
array: true,
|
||||||
|
default: "{}",
|
||||||
})
|
})
|
||||||
public excludeKeywords: string[][];
|
public excludeKeywords: string[];
|
||||||
|
|
||||||
@Column("boolean", {
|
@Column("boolean", {
|
||||||
default: false,
|
default: false,
|
||||||
|
|
|
@ -138,20 +138,6 @@ export class UserProfile {
|
||||||
})
|
})
|
||||||
public moderationNote: string | null;
|
public moderationNote: string | null;
|
||||||
|
|
||||||
// TODO: そのうち消す
|
|
||||||
@Column("jsonb", {
|
|
||||||
default: {},
|
|
||||||
comment: "The client-specific data of the User.",
|
|
||||||
})
|
|
||||||
public clientData: Record<string, any>;
|
|
||||||
|
|
||||||
// TODO: そのうち消す
|
|
||||||
@Column("jsonb", {
|
|
||||||
default: {},
|
|
||||||
comment: "The room data of the User.",
|
|
||||||
})
|
|
||||||
public room: Record<string, any>;
|
|
||||||
|
|
||||||
@Column("boolean", {
|
@Column("boolean", {
|
||||||
default: false,
|
default: false,
|
||||||
})
|
})
|
||||||
|
@ -200,12 +186,6 @@ export class UserProfile {
|
||||||
})
|
})
|
||||||
public pinnedPageId: Page["id"] | null;
|
public pinnedPageId: Page["id"] | null;
|
||||||
|
|
||||||
@OneToOne((type) => Page, {
|
|
||||||
onDelete: "SET NULL",
|
|
||||||
})
|
|
||||||
@JoinColumn()
|
|
||||||
public pinnedPage: Page | null;
|
|
||||||
|
|
||||||
@Index()
|
@Index()
|
||||||
@Column("boolean", {
|
@Column("boolean", {
|
||||||
default: false,
|
default: false,
|
||||||
|
@ -213,19 +193,28 @@ export class UserProfile {
|
||||||
})
|
})
|
||||||
public enableWordMute: boolean;
|
public enableWordMute: boolean;
|
||||||
|
|
||||||
@Column("jsonb", {
|
// whitespace: AND condition
|
||||||
default: [],
|
// array items: OR condition
|
||||||
|
// e.g., ["alpha beta", "gamma"]
|
||||||
|
// does match "alpha beta", "beta alpha alpha", "gamma alpha", "gamma epsilon"
|
||||||
|
// does not match "alpha", "beta gamma", "alpha alpha", "eplison"
|
||||||
|
@Column("text", {
|
||||||
|
array: true,
|
||||||
|
default: "{}",
|
||||||
})
|
})
|
||||||
public mutedWords: string[][];
|
public mutedWords: string[];
|
||||||
|
|
||||||
|
// array of regular expressions
|
||||||
@Column("text", {
|
@Column("text", {
|
||||||
array: true,
|
array: true,
|
||||||
nullable: false,
|
nullable: false,
|
||||||
})
|
})
|
||||||
public mutedPatterns: string[];
|
public mutedPatterns: string[];
|
||||||
|
|
||||||
@Column("jsonb", {
|
@Column("varchar", {
|
||||||
default: [],
|
length: 512,
|
||||||
|
array: true,
|
||||||
|
default: "{}",
|
||||||
comment: "List of instances muted by the user.",
|
comment: "List of instances muted by the user.",
|
||||||
})
|
})
|
||||||
public mutedInstances: string[];
|
public mutedInstances: string[];
|
||||||
|
@ -253,6 +242,13 @@ export class UserProfile {
|
||||||
})
|
})
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
public user: Relation<User>;
|
public user: Relation<User>;
|
||||||
|
|
||||||
|
@OneToOne(() => Page, {
|
||||||
|
onDelete: "SET NULL",
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
@JoinColumn()
|
||||||
|
public pinnedPage: Relation<Page | null>;
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
constructor(data: Partial<UserProfile>) {
|
constructor(data: Partial<UserProfile>) {
|
||||||
|
|
|
@ -16,8 +16,8 @@ export const AntennaRepository = db.getRepository(Antenna).extend({
|
||||||
id: antenna.id,
|
id: antenna.id,
|
||||||
createdAt: antenna.createdAt.toISOString(),
|
createdAt: antenna.createdAt.toISOString(),
|
||||||
name: antenna.name,
|
name: antenna.name,
|
||||||
keywords: antenna.keywords,
|
keywords: antenna.keywords.map((row) => row.split(" ")),
|
||||||
excludeKeywords: antenna.excludeKeywords,
|
excludeKeywords: antenna.excludeKeywords.map((row) => row.split(" ")),
|
||||||
src: antenna.src,
|
src: antenna.src,
|
||||||
userListId: antenna.userListId,
|
userListId: antenna.userListId,
|
||||||
userGroupId: userGroupJoining ? userGroupJoining.userGroupId : null,
|
userGroupId: userGroupJoining ? userGroupJoining.userGroupId : null,
|
||||||
|
|
|
@ -573,7 +573,7 @@ export const UserRepository = db.getRepository(User).extend({
|
||||||
hasUnreadNotification: this.getHasUnreadNotification(user.id),
|
hasUnreadNotification: this.getHasUnreadNotification(user.id),
|
||||||
hasPendingReceivedFollowRequest:
|
hasPendingReceivedFollowRequest:
|
||||||
this.getHasPendingReceivedFollowRequest(user.id),
|
this.getHasPendingReceivedFollowRequest(user.id),
|
||||||
mutedWords: profile?.mutedWords,
|
mutedWords: profile?.mutedWords.map((row) => row.split(" ")),
|
||||||
mutedPatterns: profile?.mutedPatterns,
|
mutedPatterns: profile?.mutedPatterns,
|
||||||
mutedInstances: profile?.mutedInstances,
|
mutedInstances: profile?.mutedInstances,
|
||||||
mutingNotificationTypes: profile?.mutingNotificationTypes,
|
mutingNotificationTypes: profile?.mutingNotificationTypes,
|
||||||
|
|
|
@ -42,25 +42,13 @@ export function generateMutedUserQuery(
|
||||||
)
|
)
|
||||||
// mute instances
|
// mute instances
|
||||||
.andWhere(
|
.andWhere(
|
||||||
new Brackets((qb) => {
|
`NOT
|
||||||
qb.andWhere("note.userHost IS NULL").orWhere(
|
ARRAY[
|
||||||
`NOT ((${mutingInstanceQuery.getQuery()})::jsonb ? note.userHost)`,
|
note."userHost",
|
||||||
);
|
note."replyUserHost",
|
||||||
}),
|
note."renoteUserHost"
|
||||||
)
|
]::character varying[]
|
||||||
.andWhere(
|
&& (${mutingInstanceQuery.getQuery()})`,
|
||||||
new Brackets((qb) => {
|
|
||||||
qb.where("note.replyUserHost IS NULL").orWhere(
|
|
||||||
`NOT ((${mutingInstanceQuery.getQuery()})::jsonb ? note.replyUserHost)`,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.andWhere(
|
|
||||||
new Brackets((qb) => {
|
|
||||||
qb.where("note.renoteUserHost IS NULL").orWhere(
|
|
||||||
`NOT ((${mutingInstanceQuery.getQuery()})::jsonb ? note.renoteUserHost)`,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
q.setParameters(mutingQuery.getParameters());
|
q.setParameters(mutingQuery.getParameters());
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Brackets, SelectQueryBuilder } from "typeorm";
|
import { Brackets, type SelectQueryBuilder } from "typeorm";
|
||||||
import { User } from "@/models/entities/user.js";
|
import type { User } from "@/models/entities/user.js";
|
||||||
import { RenoteMutings } from "@/models/index.js";
|
import { RenoteMutings } from "@/models/index.js";
|
||||||
|
|
||||||
export function generateMutedUserRenotesQueryForNotes(
|
export function generateMutedUserRenotesQueryForNotes(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Brackets, SelectQueryBuilder } from "typeorm";
|
import { Brackets, type SelectQueryBuilder } from "typeorm";
|
||||||
import { User } from "@/models/entities/user.js";
|
import type { User } from "@/models/entities/user.js";
|
||||||
import { ReplyMutings } from "@/models/index.js";
|
import { ReplyMutings } from "@/models/index.js";
|
||||||
|
|
||||||
export function generateMutedUserRepliesQueryForNotes(
|
export function generateMutedUserRepliesQueryForNotes(
|
||||||
|
|
|
@ -59,7 +59,7 @@ export default define(meta, paramDef, async (ps, me) => {
|
||||||
carefulBot: profile.carefulBot,
|
carefulBot: profile.carefulBot,
|
||||||
injectFeaturedNote: profile.injectFeaturedNote,
|
injectFeaturedNote: profile.injectFeaturedNote,
|
||||||
receiveAnnouncementEmail: profile.receiveAnnouncementEmail,
|
receiveAnnouncementEmail: profile.receiveAnnouncementEmail,
|
||||||
mutedWords: profile.mutedWords,
|
mutedWords: profile.mutedWords.map((row) => row.split(" ")),
|
||||||
mutedPatterns: profile.mutedPatterns,
|
mutedPatterns: profile.mutedPatterns,
|
||||||
mutedInstances: profile.mutedInstances,
|
mutedInstances: profile.mutedInstances,
|
||||||
mutingNotificationTypes: profile.mutingNotificationTypes,
|
mutingNotificationTypes: profile.mutingNotificationTypes,
|
||||||
|
|
|
@ -104,8 +104,22 @@ export const paramDef = {
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export default define(meta, paramDef, async (ps, user) => {
|
export default define(meta, paramDef, async (ps, user) => {
|
||||||
|
const flatten = (arr: string[][]) =>
|
||||||
|
JSON.stringify(arr) === "[[]]"
|
||||||
|
? ([] as string[])
|
||||||
|
: arr.map((row) => row.join(" "));
|
||||||
|
|
||||||
|
const keywords = flatten(
|
||||||
|
ps.keywords.map((row) => row.filter((word) => word.trim().length > 0)),
|
||||||
|
);
|
||||||
|
const excludedWords = flatten(
|
||||||
|
ps.excludeKeywords.map((row) =>
|
||||||
|
row.filter((word) => word.trim().length > 0),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
if (user.movedToUri != null) throw new ApiError(meta.errors.noSuchUserGroup);
|
if (user.movedToUri != null) throw new ApiError(meta.errors.noSuchUserGroup);
|
||||||
if (ps.keywords.length === 0) throw new ApiError(meta.errors.noKeywords);
|
if (keywords.length === 0) throw new ApiError(meta.errors.noKeywords);
|
||||||
let userList;
|
let userList;
|
||||||
let userGroupJoining;
|
let userGroupJoining;
|
||||||
|
|
||||||
|
@ -146,10 +160,10 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
src: ps.src,
|
src: ps.src,
|
||||||
userListId: userList ? userList.id : null,
|
userListId: userList ? userList.id : null,
|
||||||
userGroupJoiningId: userGroupJoining ? userGroupJoining.id : null,
|
userGroupJoiningId: userGroupJoining ? userGroupJoining.id : null,
|
||||||
keywords: ps.keywords,
|
keywords: keywords,
|
||||||
excludeKeywords: ps.excludeKeywords,
|
excludeKeywords: excludedWords,
|
||||||
users: ps.users,
|
users: ps.users,
|
||||||
instances: ps.instances,
|
instances: ps.instances.filter((instance) => instance.trim().length > 0),
|
||||||
caseSensitive: ps.caseSensitive,
|
caseSensitive: ps.caseSensitive,
|
||||||
withReplies: ps.withReplies,
|
withReplies: ps.withReplies,
|
||||||
withFile: ps.withFile,
|
withFile: ps.withFile,
|
||||||
|
|
|
@ -100,6 +100,20 @@ export const paramDef = {
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export default define(meta, paramDef, async (ps, user) => {
|
export default define(meta, paramDef, async (ps, user) => {
|
||||||
|
const flatten = (arr: string[][]) =>
|
||||||
|
JSON.stringify(arr) === "[[]]"
|
||||||
|
? ([] as string[])
|
||||||
|
: arr.map((row) => row.join(" "));
|
||||||
|
|
||||||
|
const keywords = flatten(
|
||||||
|
ps.keywords.map((row) => row.filter((word) => word.trim().length > 0)),
|
||||||
|
);
|
||||||
|
const excludedWords = flatten(
|
||||||
|
ps.excludeKeywords.map((row) =>
|
||||||
|
row.filter((word) => word.trim().length > 0),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
// Fetch the antenna
|
// Fetch the antenna
|
||||||
const antenna = await Antennas.findOneBy({
|
const antenna = await Antennas.findOneBy({
|
||||||
id: ps.antennaId,
|
id: ps.antennaId,
|
||||||
|
@ -138,10 +152,10 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
src: ps.src,
|
src: ps.src,
|
||||||
userListId: userList ? userList.id : null,
|
userListId: userList ? userList.id : null,
|
||||||
userGroupJoiningId: userGroupJoining ? userGroupJoining.id : null,
|
userGroupJoiningId: userGroupJoining ? userGroupJoining.id : null,
|
||||||
keywords: ps.keywords,
|
keywords: keywords,
|
||||||
excludeKeywords: ps.excludeKeywords,
|
excludeKeywords: excludedWords,
|
||||||
users: ps.users,
|
users: ps.users,
|
||||||
instances: ps.instances,
|
instances: ps.instances.filter((instance) => instance.trim().length > 0),
|
||||||
caseSensitive: ps.caseSensitive,
|
caseSensitive: ps.caseSensitive,
|
||||||
withReplies: ps.withReplies,
|
withReplies: ps.withReplies,
|
||||||
withFile: ps.withFile,
|
withFile: ps.withFile,
|
||||||
|
|
|
@ -125,7 +125,8 @@ export default define(meta, paramDef, async (ps, user) => {
|
||||||
query.andWhere(
|
query.andWhere(
|
||||||
new Brackets((qb) => {
|
new Brackets((qb) => {
|
||||||
qb.andWhere("notifier.host IS NULL").orWhere(
|
qb.andWhere("notifier.host IS NULL").orWhere(
|
||||||
`NOT (( ${mutingInstanceQuery.getQuery()} )::jsonb ? notifier.host)`,
|
`NOT EXISTS (SELECT 1 FROM "user_profile" WHERE "userId" = :muterId AND notifier.host = ANY("mutedInstances"))`,
|
||||||
|
{ muterId: user.id },
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
|
@ -178,26 +178,11 @@ export default define(meta, paramDef, async (ps, _user, token) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ps.mutedWords !== undefined) {
|
if (ps.mutedWords !== undefined) {
|
||||||
// for backward compatibility
|
const flatten = (arr: string[][]) =>
|
||||||
for (const item of ps.mutedWords) {
|
JSON.stringify(arr) === "[[]]"
|
||||||
if (Array.isArray(item)) continue;
|
? ([] as string[])
|
||||||
|
: arr.map((row) => row.join(" "));
|
||||||
const regexp = item.match(/^\/(.+)\/(.*)$/);
|
profileUpdates.mutedWords = flatten(ps.mutedWords);
|
||||||
if (!regexp) throw new ApiError(meta.errors.invalidRegexp);
|
|
||||||
|
|
||||||
try {
|
|
||||||
new RegExp(regexp[1], regexp[2]);
|
|
||||||
} catch (err) {
|
|
||||||
throw new ApiError(meta.errors.invalidRegexp);
|
|
||||||
}
|
|
||||||
|
|
||||||
profileUpdates.mutedPatterns = profileUpdates.mutedPatterns ?? [];
|
|
||||||
profileUpdates.mutedPatterns.push(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
profileUpdates.mutedWords = ps.mutedWords.filter((item) =>
|
|
||||||
Array.isArray(item),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
profileUpdates.mutedWords !== undefined ||
|
profileUpdates.mutedWords !== undefined ||
|
||||||
|
|
Loading…
Reference in a new issue