From 89924b587a378e078a5930972dfac68bd553a72b Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Wed, 4 Oct 2023 04:35:58 +0200 Subject: [PATCH] add: speakAsCat extension --- locales/en-US.yml | 2 ++ .../backend/migration/1696386694000-speakAsCat.js | 12 ++++++++++++ .../src/core/activitypub/ApRendererService.ts | 4 ++++ .../src/core/activitypub/models/ApPersonService.ts | 1 + .../backend/src/core/entities/NoteEntityService.ts | 2 +- .../backend/src/core/entities/UserEntityService.ts | 1 + packages/backend/src/models/User.ts | 6 ++++++ packages/backend/src/models/json-schema/user.ts | 4 ++++ .../backend/src/server/api/endpoints/i/update.ts | 2 ++ packages/backend/test/e2e/users.ts | 4 ++++ packages/frontend/.storybook/fakes.ts | 1 + packages/frontend/src/pages/settings/profile.vue | 3 +++ .../megalodon/src/misskey/entities/userDetail.ts | 1 + packages/misskey-js/etc/misskey-js.api.md | 2 ++ packages/misskey-js/src/api.types.ts | 1 + packages/misskey-js/src/entities.ts | 1 + 16 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 packages/backend/migration/1696386694000-speakAsCat.js diff --git a/locales/en-US.yml b/locales/en-US.yml index 2e6cb32e3..e0c9c551e 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -164,6 +164,8 @@ flagAsBot: "Mark this account as a bot" flagAsBotDescription: "Enable this option if this account is controlled by a program. If enabled, it will act as a flag for other developers to prevent endless interaction chains with other bots and adjust Misskey's internal systems to treat this account as a bot." flagAsCat: "Mark this account as a cat" flagAsCatDescription: "Enable this option to mark this account as a cat." +flagSpeakAsCat: "Speak as a cat" +flagSpeakAsCatDescription: "Your posts will get nyanified when in cat mode" flagShowTimelineReplies: "Show replies in timeline" flagShowTimelineRepliesDescription: "Shows replies of users to notes of other users in the timeline if turned on." autoAcceptFollowed: "Automatically approve follow requests from users you're following" diff --git a/packages/backend/migration/1696386694000-speakAsCat.js b/packages/backend/migration/1696386694000-speakAsCat.js new file mode 100644 index 000000000..d68b9401b --- /dev/null +++ b/packages/backend/migration/1696386694000-speakAsCat.js @@ -0,0 +1,12 @@ +export class SpeakAsCat1696386694000 { + name = "SpeakAsCat1696386694000"; + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" ADD "speakAsCat" boolean NOT NULL DEFAULT true`); + await queryRunner.query(`COMMENT ON COLUMN "user"."speakAsCat" IS 'Whether to speak as a cat if chosen.'`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "speakAsCat"`); + } +} diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index 43e4ddbf3..155aee39a 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -501,6 +501,7 @@ export class ApRendererService { discoverable: user.isExplorable, publicKey: this.renderKey(user, keypair, '#main-key'), isCat: user.isCat, + speakAsCat: user.speakAsCat, attachment: attachment.length ? attachment : undefined, }; @@ -646,6 +647,9 @@ export class ApRendererService { '_misskey_reaction': 'misskey:_misskey_reaction', '_misskey_votes': 'misskey:_misskey_votes', 'isCat': 'misskey:isCat', + // Firefish + firefish: "https://joinfirefish.org/ns#", + speakAsCat: "firefish:speakAsCat", // vcard vcard: 'http://www.w3.org/2006/vcard/ns#', }, diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index 2469583e5..a68e38cd6 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -326,6 +326,7 @@ export class ApPersonService implements OnModuleInit { tags, isBot, isCat: (person as any).isCat === true, + speakAsCat: (person as any).speakAsCat != null ? (person as any).speakAsCat === true : (person as any).isCat === true, emojis, })) as MiRemoteUser; diff --git a/packages/backend/src/core/entities/NoteEntityService.ts b/packages/backend/src/core/entities/NoteEntityService.ts index 026f84bb3..7ba7bce41 100644 --- a/packages/backend/src/core/entities/NoteEntityService.ts +++ b/packages/backend/src/core/entities/NoteEntityService.ts @@ -364,7 +364,7 @@ export class NoteEntityService implements OnModuleInit { } : {}), }); - if (packed.user.isCat && packed.text) { + if (packed.user.speakAsCat && packed.text) { const tokens = packed.text ? mfm.parse(packed.text) : []; function nyaizeNode(node: mfm.MfmNode) { if (node.type === 'quote') return; diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index cdd1182f6..714459d76 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -352,6 +352,7 @@ export class UserEntityService implements OnModuleInit { createdAt: user.createdAt.toISOString(), isBot: user.isBot ?? falsy, isCat: user.isCat ?? falsy, + speakAsCat: user.speakAsCat ?? falsy, instance: user.host ? this.federatedInstanceService.federatedInstanceCache.fetch(user.host).then(instance => instance ? { name: instance.name, softwareName: instance.softwareName, diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts index 8f0122a90..d1dd15919 100644 --- a/packages/backend/src/models/User.ts +++ b/packages/backend/src/models/User.ts @@ -174,6 +174,12 @@ export class MiUser { }) public isCat: boolean; + @Column('boolean', { + default: false, + comment: 'Whether the User speaks in nya.', + }) + public speakAsCat: boolean; + @Column('boolean', { default: false, comment: 'Whether the User is the root.', diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts index 79b14bb65..a8fb34acb 100644 --- a/packages/backend/src/models/json-schema/user.ts +++ b/packages/backend/src/models/json-schema/user.ts @@ -55,6 +55,10 @@ export const packedUserLiteSchema = { type: 'boolean', nullable: false, optional: true, }, + speakAsCat: { + type: 'boolean', + nullable: false, optional: true, + }, onlineStatus: { type: 'string', format: 'url', diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index e5bf27d22..93897b9c8 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -156,6 +156,7 @@ export const paramDef = { preventAiLearning: { type: 'boolean' }, isBot: { type: 'boolean' }, isCat: { type: 'boolean' }, + speakAsCat: { type: 'boolean' }, injectFeaturedNote: { type: 'boolean' }, receiveAnnouncementEmail: { type: 'boolean' }, alwaysMarkNsfw: { type: 'boolean' }, @@ -259,6 +260,7 @@ export default class extends Endpoint { // eslint- if (typeof ps.noCrawle === 'boolean') profileUpdates.noCrawle = ps.noCrawle; if (typeof ps.preventAiLearning === 'boolean') profileUpdates.preventAiLearning = ps.preventAiLearning; if (typeof ps.isCat === 'boolean') updates.isCat = ps.isCat; + if (typeof ps.speakAsCat === 'boolean') updates.speakAsCat = ps.speakAsCat; if (typeof ps.injectFeaturedNote === 'boolean') profileUpdates.injectFeaturedNote = ps.injectFeaturedNote; if (typeof ps.receiveAnnouncementEmail === 'boolean') profileUpdates.receiveAnnouncementEmail = ps.receiveAnnouncementEmail; if (typeof ps.alwaysMarkNsfw === 'boolean') { diff --git a/packages/backend/test/e2e/users.ts b/packages/backend/test/e2e/users.ts index 0f5d5f734..93fbdaaa3 100644 --- a/packages/backend/test/e2e/users.ts +++ b/packages/backend/test/e2e/users.ts @@ -70,6 +70,7 @@ describe('ユーザー', () => { avatarBlurhash: user.avatarBlurhash, isBot: user.isBot, isCat: user.isCat, + speakAsCat: user.speakAsCat, instance: user.instance, emojis: user.emojis, onlineStatus: user.onlineStatus, @@ -350,6 +351,7 @@ describe('ユーザー', () => { assert.strictEqual(response.avatarBlurhash, null); assert.strictEqual(response.isBot, false); assert.strictEqual(response.isCat, false); + assert.strictEqual(response.speakAsCat, false); assert.strictEqual(response.instance, undefined); assert.deepStrictEqual(response.emojis, {}); assert.strictEqual(response.onlineStatus, 'unknown'); @@ -481,6 +483,8 @@ describe('ユーザー', () => { { parameters: (): object => ({ isBot: false }) }, { parameters: (): object => ({ isCat: true }) }, { parameters: (): object => ({ isCat: false }) }, + { parameters: (): object => ({ speakAsCat: true }) }, + { parameters: (): object => ({ speakAsCat: false }) }, { parameters: (): object => ({ injectFeaturedNote: true }) }, { parameters: (): object => ({ injectFeaturedNote: false }) }, { parameters: (): object => ({ receiveAnnouncementEmail: true }) }, diff --git a/packages/frontend/.storybook/fakes.ts b/packages/frontend/.storybook/fakes.ts index 811c24392..47f9a53da 100644 --- a/packages/frontend/.storybook/fakes.ts +++ b/packages/frontend/.storybook/fakes.ts @@ -99,6 +99,7 @@ export function userDetailed(id = 'someuserid', username = 'miskist', host = 'mi isBlocking: false, isBot: false, isCat: false, + speakAsCat: false, isFollowed: false, isFollowing: false, isLocked: false, diff --git a/packages/frontend/src/pages/settings/profile.vue b/packages/frontend/src/pages/settings/profile.vue index b6377d8b9..fc406efae 100644 --- a/packages/frontend/src/pages/settings/profile.vue +++ b/packages/frontend/src/pages/settings/profile.vue @@ -93,6 +93,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.flagAsCat }} + {{ i18n.ts.flagSpeakAsCat }} {{ i18n.ts.flagAsBot }}
@@ -141,6 +142,7 @@ const profile = reactive({ lang: $i.lang, isBot: $i.isBot, isCat: $i.isCat, + speakAsCat: $i.speakAsCat, }); watch(() => profile, () => { @@ -190,6 +192,7 @@ function save() { lang: profile.lang || null, isBot: !!profile.isBot, isCat: !!profile.isCat, + speakAsCat: !!profile.speakAsCat, }); claimAchievement('profileFilled'); if (profile.name === 'syuilo' || profile.name === 'しゅいろ') { diff --git a/packages/megalodon/src/misskey/entities/userDetail.ts b/packages/megalodon/src/misskey/entities/userDetail.ts index bf0e3c2c2..0a5927860 100644 --- a/packages/megalodon/src/misskey/entities/userDetail.ts +++ b/packages/megalodon/src/misskey/entities/userDetail.ts @@ -13,6 +13,7 @@ namespace MisskeyEntity { isModerator: boolean isBot: boolean isCat: boolean + speakAsCat: boolean emojis: Array | { [key: string]: string } createdAt: string bannerUrl: string diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index f0fc47c20..5fb80c6a3 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -1541,6 +1541,7 @@ export type Endpoints = { noCrawle?: boolean; isBot?: boolean; isCat?: boolean; + speakAsCat?: boolean; injectFeaturedNote?: boolean; receiveAnnouncementEmail?: boolean; alwaysMarkNsfw?: boolean; @@ -2915,6 +2916,7 @@ type UserDetailed = UserLite & { isBlocking: boolean; isBot: boolean; isCat: boolean; + speakAsCat: boolean; isFollowed: boolean; isFollowing: boolean; isLocked: boolean; diff --git a/packages/misskey-js/src/api.types.ts b/packages/misskey-js/src/api.types.ts index 7a8b6872d..b3837369e 100644 --- a/packages/misskey-js/src/api.types.ts +++ b/packages/misskey-js/src/api.types.ts @@ -426,6 +426,7 @@ export type Endpoints = { noCrawle?: boolean; isBot?: boolean; isCat?: boolean; + speakAsCat?: boolean; injectFeaturedNote?: boolean; receiveAnnouncementEmail?: boolean; alwaysMarkNsfw?: boolean; diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts index 301d4bc3a..59df4582d 100644 --- a/packages/misskey-js/src/entities.ts +++ b/packages/misskey-js/src/entities.ts @@ -50,6 +50,7 @@ export type UserDetailed = UserLite & { isBlocking: boolean; isBot: boolean; isCat: boolean; + speakAsCat: boolean; isFollowed: boolean; isFollowing: boolean; isLocked: boolean;