diff --git a/locales/en-US.yml b/locales/en-US.yml index 730e7450d..2726641a6 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -745,6 +745,8 @@ thisIsExperimentalFeature: "This is an experimental feature. Its functionality i developer: "Developer" makeExplorable: "Make account visible in \"Explore\"" makeExplorableDescription: "If you turn this off, your account will not show up in the \"Explore\" section." +makeIndexable: "Make public notes indexable" +makeIndexableDescription: "Allow note search to index your public notes." showGapBetweenNotesInTimeline: "Show a gap between posts on the timeline" duplicate: "Duplicate" left: "Left" diff --git a/locales/index.d.ts b/locales/index.d.ts index d4934b77a..dfdf3119b 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -748,6 +748,8 @@ export interface Locale { "developer": string; "makeExplorable": string; "makeExplorableDescription": string; + "makeIndexable": string; + "makeIndexableDescription": string; "showGapBetweenNotesInTimeline": string; "duplicate": string; "left": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 36521c881..fb2a64b39 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -745,6 +745,8 @@ thisIsExperimentalFeature: "これは実験的な機能です。仕様が変更 developer: "開発者" makeExplorable: "アカウントを見つけやすくする" makeExplorableDescription: "オフにすると、「みつける」にアカウントが載らなくなります。" +makeIndexable: "公開ノートをインデックス化" +makeIndexableDescription: "ノート検索で公開ノートにインデックスを付けられるようにする。" showGapBetweenNotesInTimeline: "タイムラインのノートを離して表示" duplicate: "複製" left: "左" diff --git a/packages/backend/migration/1699376974000-isIndexable.js b/packages/backend/migration/1699376974000-isIndexable.js new file mode 100644 index 000000000..ae826924a --- /dev/null +++ b/packages/backend/migration/1699376974000-isIndexable.js @@ -0,0 +1,11 @@ +export class IsIndexable1699376974000 { + name = 'IsIndexable1699376974000' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" ADD "isIndexable" boolean NOT NULL DEFAULT true`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "isIndexable"`); + } +} diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts index 40d1db600..3e7bba9e1 100644 --- a/packages/backend/src/core/NoteCreateService.ts +++ b/packages/backend/src/core/NoteCreateService.ts @@ -223,8 +223,7 @@ export class NoteCreateService implements OnApplicationShutdown { username: MiUser['username']; host: MiUser['host']; isBot: MiUser['isBot']; - isCat: MiUser['isCat']; - speakAsCat: MiUser['speakAsCat']; + isIndexable: MiUser['isIndexable']; }, data: Option, silent = false): Promise { // チャンネル外にリプライしたら対象のスコープに合わせる // (クライアントサイドでやっても良い処理だと思うけどとりあえずサーバーサイドで) @@ -482,6 +481,7 @@ export class NoteCreateService implements OnApplicationShutdown { username: MiUser['username']; host: MiUser['host']; isBot: MiUser['isBot']; + isIndexable: MiUser['isIndexable']; }, data: Option, silent: boolean, tags: string[], mentionedUsers: MinimumUser[]) { const meta = await this.metaService.fetch(); @@ -712,7 +712,7 @@ export class NoteCreateService implements OnApplicationShutdown { } // Register to search database - this.index(note); + if (user.isIndexable) this.index(note); } @bindThis diff --git a/packages/backend/src/core/NoteEditService.ts b/packages/backend/src/core/NoteEditService.ts index e88ab053e..23ce2ab7a 100644 --- a/packages/backend/src/core/NoteEditService.ts +++ b/packages/backend/src/core/NoteEditService.ts @@ -224,6 +224,7 @@ export class NoteEditService implements OnApplicationShutdown { username: MiUser['username']; host: MiUser['host']; isBot: MiUser['isBot']; + isIndexable: MiUser['isIndexable']; }, editid: MiNote['id'], data: Option, silent = false): Promise { if (!editid) { throw new Error('fail'); @@ -498,6 +499,7 @@ export class NoteEditService implements OnApplicationShutdown { username: MiUser['username']; host: MiUser['host']; isBot: MiUser['isBot']; + isIndexable: MiUser['isIndexable']; }, data: Option, silent: boolean, tags: string[], mentionedUsers: MinimumUser[]) { // Register host if (this.userEntityService.isRemoteUser(user)) { @@ -686,7 +688,7 @@ export class NoteEditService implements OnApplicationShutdown { } // Register to search database - this.index(note); + if (user.isIndexable) this.index(note); } @bindThis diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index 8facc2536..fb32eab20 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -506,6 +506,7 @@ export class ApRendererService { discoverable: user.isExplorable, publicKey: this.renderKey(user, keypair, '#main-key'), isCat: user.isCat, + isIndexable: user.isIndexable, speakAsCat: user.speakAsCat, attachment: attachment.length ? attachment : undefined, }; diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index cfb380a32..02bacacc6 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -310,6 +310,7 @@ export class ApPersonService implements OnModuleInit { backgroundId: null, lastFetchedAt: new Date(), name: truncate(person.name, nameLength), + isIndexable: person.isIndexable ?? true, isLocked: person.manuallyApprovesFollowers, movedToUri: person.movedTo, movedAt: person.movedTo ? new Date() : null, @@ -476,6 +477,7 @@ export class ApPersonService implements OnModuleInit { isBot: getApType(object) === 'Service' || getApType(object) === 'Application', isCat: (person as any).isCat === true, speakAsCat: (person as any).speakAsCat != null ? (person as any).speakAsCat === true : (person as any).isCat === true, + isIndexable: person.isIndexable ?? true, isLocked: person.manuallyApprovesFollowers, movedToUri: person.movedTo ?? null, alsoKnownAs: person.alsoKnownAs ?? null, diff --git a/packages/backend/src/core/activitypub/type.ts b/packages/backend/src/core/activitypub/type.ts index 62d7ef93f..02667214d 100644 --- a/packages/backend/src/core/activitypub/type.ts +++ b/packages/backend/src/core/activitypub/type.ts @@ -184,6 +184,7 @@ export interface IActor extends IObject { }; 'vcard:bday'?: string; 'vcard:Address'?: string; + isIndexable?: boolean; listenbrainz?: string; backgroundUrl?: string; } diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index e40ff27c7..06ce60c7c 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -399,6 +399,7 @@ export class UserEntityService implements OnModuleInit { }))) : [], isBot: user.isBot, isCat: user.isCat, + isIndexable: user.isIndexable, isSilenced: user.isSilenced || this.roleService.getUserPolicies(user.id).then(r => !r.canPublicNote), speakAsCat: user.speakAsCat ?? false, approved: user.approved, diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts index c4bc98fc1..bff2b142e 100644 --- a/packages/backend/src/models/User.ts +++ b/packages/backend/src/models/User.ts @@ -188,6 +188,12 @@ export class MiUser { }) public isSilenced: boolean; + @Column('boolean', { + default: true, + comment: 'Whether the User\'s notes get indexed.', + }) + public isIndexable: boolean; + @Column('boolean', { default: false, comment: 'Whether the User is locked.', diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts index e1b626189..aa293d583 100644 --- a/packages/backend/src/models/json-schema/user.ts +++ b/packages/backend/src/models/json-schema/user.ts @@ -79,6 +79,10 @@ export const packedUserLiteSchema = { type: 'boolean', nullable: false, optional: false, }, + isIndexable: { + type: 'boolean', + nullable: false, optional: false, + }, isBot: { type: 'boolean', nullable: false, optional: true, diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index 373614f78..aa4dd0511 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -177,6 +177,7 @@ export const paramDef = { autoAcceptFollowed: { type: 'boolean' }, noCrawle: { type: 'boolean' }, preventAiLearning: { type: 'boolean' }, + isIndexable: { type: 'boolean' }, isBot: { type: 'boolean' }, isCat: { type: 'boolean' }, speakAsCat: { type: 'boolean' }, @@ -278,6 +279,7 @@ export default class extends Endpoint { // eslint- if (typeof ps.isExplorable === 'boolean') updates.isExplorable = ps.isExplorable; if (typeof ps.hideOnlineStatus === 'boolean') updates.hideOnlineStatus = ps.hideOnlineStatus; if (typeof ps.publicReactions === 'boolean') profileUpdates.publicReactions = ps.publicReactions; + if (typeof ps.isIndexable === 'boolean') updates.isIndexable = ps.isIndexable; if (typeof ps.isBot === 'boolean') updates.isBot = ps.isBot; if (typeof ps.carefulBot === 'boolean') profileUpdates.carefulBot = ps.carefulBot; if (typeof ps.autoAcceptFollowed === 'boolean') profileUpdates.autoAcceptFollowed = ps.autoAcceptFollowed; diff --git a/packages/frontend/src/pages/settings/privacy.vue b/packages/frontend/src/pages/settings/privacy.vue index 1ec8aee0a..e7414acd2 100644 --- a/packages/frontend/src/pages/settings/privacy.vue +++ b/packages/frontend/src/pages/settings/privacy.vue @@ -33,6 +33,10 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts.preventAiLearning }}{{ i18n.ts.beta }} + + {{ i18n.ts.makeIndexable }} + + {{ i18n.ts.makeExplorable }} @@ -82,6 +86,7 @@ let autoAcceptFollowed = $ref($i.autoAcceptFollowed); let noCrawle = $ref($i.noCrawle); let preventAiLearning = $ref($i.preventAiLearning); let isExplorable = $ref($i.isExplorable); +let isIndexable = $ref($i.isIndexable); let hideOnlineStatus = $ref($i.hideOnlineStatus); let publicReactions = $ref($i.publicReactions); let ffVisibility = $ref($i.ffVisibility); @@ -98,6 +103,7 @@ function save() { noCrawle: !!noCrawle, preventAiLearning: !!preventAiLearning, isExplorable: !!isExplorable, + isIndexable: !!isIndexable, hideOnlineStatus: !!hideOnlineStatus, publicReactions: !!publicReactions, ffVisibility: ffVisibility, diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts index 9c01446fa..dee1aed40 100644 --- a/packages/misskey-js/src/entities.ts +++ b/packages/misskey-js/src/entities.ts @@ -37,6 +37,7 @@ export type UserLite = { }; isCat?: boolean; isBot?: boolean; + isIndexable?: boolean; }; export type UserDetailed = UserLite & { @@ -65,6 +66,7 @@ export type UserDetailed = UserLite & { speakAsCat: boolean; isFollowed: boolean; isFollowing: boolean; + isIndexable: boolean; isLocked: boolean; isModerator: boolean; isMuted: boolean;