From 5eff4da27b382226bcd0be0772dac6105ade4216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=81=E5=91=A8=E9=83=A8=E8=90=BD?= Date: Sat, 13 Apr 2024 08:59:11 +0800 Subject: [PATCH 1/9] feat: antenna limit --- locales/en-US.yml | 1 + locales/zh-CN.yml | 1 + packages/backend-rs/index.d.ts | 1 + packages/backend-rs/src/model/entity/meta.rs | 2 ++ .../migration/1712937600000-antennaLimit.ts | 19 +++++++++++++++++++ packages/backend/src/models/entities/meta.ts | 6 ++++++ .../src/server/api/endpoints/admin/meta.ts | 6 ++++++ .../server/api/endpoints/admin/update-meta.ts | 5 +++++ .../server/api/endpoints/antennas/create.ts | 5 ++++- .../backend/src/server/api/endpoints/meta.ts | 6 ++++++ packages/client/src/pages/admin/settings.vue | 16 ++++++++++++++++ packages/firefish-js/src/entities.ts | 1 + 12 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 packages/backend/src/migration/1712937600000-antennaLimit.ts diff --git a/locales/en-US.yml b/locales/en-US.yml index f8da18450c..a8663375a8 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -394,6 +394,7 @@ enableRegistration: "Enable new user registration" invite: "Invite" driveCapacityPerLocalAccount: "Drive capacity per local user" driveCapacityPerRemoteAccount: "Drive capacity per remote user" +antennaLimit: "The maximum number of antennas that each user can create" inMb: "In megabytes" iconUrl: "Icon URL" bannerUrl: "Banner image URL" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index a8510612dc..9e7a0ed19e 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -340,6 +340,7 @@ invite: "邀请" driveCapacityPerLocalAccount: "每个本地用户的网盘容量" driveCapacityPerRemoteAccount: "每个远程用户的网盘容量" inMb: "以兆字节 (MegaByte) 为单位" +antennaLimit: "每个用户最多可以创建的天线数量" iconUrl: "图标 URL" bannerUrl: "横幅图 URL" backgroundImageUrl: "背景图 URL" diff --git a/packages/backend-rs/index.d.ts b/packages/backend-rs/index.d.ts index 617bedf5b9..509c3d912d 100644 --- a/packages/backend-rs/index.d.ts +++ b/packages/backend-rs/index.d.ts @@ -443,6 +443,7 @@ export interface Meta { recaptchaSecretKey: string | null localDriveCapacityMb: number remoteDriveCapacityMb: number + antennaLimit: number summalyProxy: string | null enableEmail: boolean email: string | null diff --git a/packages/backend-rs/src/model/entity/meta.rs b/packages/backend-rs/src/model/entity/meta.rs index b9a89914bd..7d0972b844 100644 --- a/packages/backend-rs/src/model/entity/meta.rs +++ b/packages/backend-rs/src/model/entity/meta.rs @@ -50,6 +50,8 @@ pub struct Model { pub local_drive_capacity_mb: i32, #[sea_orm(column_name = "remoteDriveCapacityMb")] pub remote_drive_capacity_mb: i32, + #[sea_orm(column_name = "antennaLimit")] + pub antenna_limit: i32, #[sea_orm(column_name = "summalyProxy")] pub summaly_proxy: Option, #[sea_orm(column_name = "enableEmail")] diff --git a/packages/backend/src/migration/1712937600000-antennaLimit.ts b/packages/backend/src/migration/1712937600000-antennaLimit.ts new file mode 100644 index 0000000000..cd8f9ff658 --- /dev/null +++ b/packages/backend/src/migration/1712937600000-antennaLimit.ts @@ -0,0 +1,19 @@ +import type { MigrationInterface, QueryRunner } from "typeorm"; + +export class antennaLimit1712937600000 implements MigrationInterface { + async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "meta" ADD "antennaLimit" integer NOT NULL DEFAULT 5`, + undefined, + ); + await queryRunner.query( + `COMMENT ON COLUMN "meta"."antennaLimit" IS 'Antenna Limit'`, + ); + } + async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "meta" DROP COLUMN "antennaLimit"`, + undefined, + ); + } +} diff --git a/packages/backend/src/models/entities/meta.ts b/packages/backend/src/models/entities/meta.ts index cdb8e14c3f..5e267a8e24 100644 --- a/packages/backend/src/models/entities/meta.ts +++ b/packages/backend/src/models/entities/meta.ts @@ -276,6 +276,12 @@ export class Meta { }) public remoteDriveCapacityMb: number; + @Column("integer", { + default: 5, + comment: "Antenna Limit", + }) + public antennaLimit: number; + @Column("varchar", { length: 128, nullable: true, diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index a22fbab8f1..1f382f1254 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -24,6 +24,11 @@ export const meta = { optional: false, nullable: false, }, + antennaLimit: { + type: "number", + optional: false, + nullable: false, + }, cacheRemoteFiles: { type: "boolean", optional: false, @@ -487,6 +492,7 @@ export default define(meta, paramDef, async () => { enableGuestTimeline: instance.enableGuestTimeline, driveCapacityPerLocalUserMb: instance.localDriveCapacityMb, driveCapacityPerRemoteUserMb: instance.remoteDriveCapacityMb, + antennaLimit: instance.antennaLimit, emailRequiredForSignup: instance.emailRequiredForSignup, enableHcaptcha: instance.enableHcaptcha, hcaptchaSiteKey: instance.hcaptchaSiteKey, diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index 604ef3a0fc..e5234ea720 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -94,6 +94,7 @@ export const paramDef = { defaultDarkTheme: { type: "string", nullable: true }, localDriveCapacityMb: { type: "integer" }, remoteDriveCapacityMb: { type: "integer" }, + antennaLimit: { type: "integer" }, cacheRemoteFiles: { type: "boolean" }, markLocalFilesNsfwByDefault: { type: "boolean" }, emailRequiredForSignup: { type: "boolean" }, @@ -327,6 +328,10 @@ export default define(meta, paramDef, async (ps, me) => { set.remoteDriveCapacityMb = ps.remoteDriveCapacityMb; } + if (ps.antennaLimit !== undefined) { + set.antennaLimit = ps.antennaLimit; + } + if (ps.cacheRemoteFiles !== undefined) { set.cacheRemoteFiles = ps.cacheRemoteFiles; } diff --git a/packages/backend/src/server/api/endpoints/antennas/create.ts b/packages/backend/src/server/api/endpoints/antennas/create.ts index 792301d4de..792c5e30b4 100644 --- a/packages/backend/src/server/api/endpoints/antennas/create.ts +++ b/packages/backend/src/server/api/endpoints/antennas/create.ts @@ -3,6 +3,7 @@ import { genId } from "backend-rs"; import { Antennas, UserLists, UserGroupJoinings } from "@/models/index.js"; import { ApiError } from "@/server/api/error.js"; import { publishInternalEvent } from "@/services/stream.js"; +import { fetchMeta } from "@/misc/fetch-meta.js"; export const meta = { tags: ["antennas"], @@ -109,10 +110,12 @@ export default define(meta, paramDef, async (ps, user) => { let userList; let userGroupJoining; + const instance = await fetchMeta(true); + const antennas = await Antennas.findBy({ userId: user.id, }); - if (antennas.length > 5 && !user.isAdmin) { + if (antennas.length >= instance.antennaLimit) { throw new ApiError(meta.errors.tooManyAntennas); } diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index 2a674b52c3..cb494bf27e 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -126,6 +126,11 @@ export const meta = { optional: false, nullable: false, }, + antennaLimit: { + type: "number", + optional: false, + nullable: false, + }, cacheRemoteFiles: { type: "boolean", optional: false, @@ -445,6 +450,7 @@ export default define(meta, paramDef, async (ps, me) => { enableGuestTimeline: instance.enableGuestTimeline, driveCapacityPerLocalUserMb: instance.localDriveCapacityMb, driveCapacityPerRemoteUserMb: instance.remoteDriveCapacityMb, + antennaLimit: instance.antennaLimit, emailRequiredForSignup: instance.emailRequiredForSignup, enableHcaptcha: instance.enableHcaptcha, hcaptchaSiteKey: instance.hcaptchaSiteKey, diff --git a/packages/client/src/pages/admin/settings.vue b/packages/client/src/pages/admin/settings.vue index f69c4fb23b..1c2188daac 100644 --- a/packages/client/src/pages/admin/settings.vue +++ b/packages/client/src/pages/admin/settings.vue @@ -350,6 +350,19 @@ + + + + + + + @@ -502,6 +515,7 @@ const cacheRemoteFiles = ref(false); const markLocalFilesNsfwByDefault = ref(false); const localDriveCapacityMb = ref(0); const remoteDriveCapacityMb = ref(0); +const antennaLimit = ref(0); const enableRegistration = ref(false); const emailRequiredForSignup = ref(false); const enableServiceWorker = ref(false); @@ -579,6 +593,7 @@ async function init() { markLocalFilesNsfwByDefault.value = meta.markLocalFilesNsfwByDefault; localDriveCapacityMb.value = meta.driveCapacityPerLocalUserMb; remoteDriveCapacityMb.value = meta.driveCapacityPerRemoteUserMb; + antennaLimit.value = meta.antennaLimit; enableRegistration.value = !meta.disableRegistration; emailRequiredForSignup.value = meta.emailRequiredForSignup; enableServiceWorker.value = meta.enableServiceWorker; @@ -631,6 +646,7 @@ function save() { markLocalFilesNsfwByDefault: markLocalFilesNsfwByDefault.value, localDriveCapacityMb: localDriveCapacityMb.value, remoteDriveCapacityMb: remoteDriveCapacityMb.value, + antennaLimit: antennaLimit.value, disableRegistration: !enableRegistration.value, emailRequiredForSignup: emailRequiredForSignup.value, enableServiceWorker: enableServiceWorker.value, diff --git a/packages/firefish-js/src/entities.ts b/packages/firefish-js/src/entities.ts index ce940a1481..6f9d6b400b 100644 --- a/packages/firefish-js/src/entities.ts +++ b/packages/firefish-js/src/entities.ts @@ -341,6 +341,7 @@ export type LiteInstanceMetadata = { disableGlobalTimeline: boolean; driveCapacityPerLocalUserMb: number; driveCapacityPerRemoteUserMb: number; + antennaLimit: number; enableHcaptcha: boolean; hcaptchaSiteKey: string | null; enableRecaptcha: boolean; From f0a50bc2889416c8fb741147523b077719621130 Mon Sep 17 00:00:00 2001 From: Lhcfl Date: Sun, 14 Apr 2024 13:59:27 +0800 Subject: [PATCH 2/9] feat: show MkRemoteCaution in note history page --- packages/client/src/pages/note-history.vue | 74 ++++++++++++---------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/packages/client/src/pages/note-history.vue b/packages/client/src/pages/note-history.vue index f6fbf517a3..33cae5860a 100644 --- a/packages/client/src/pages/note-history.vue +++ b/packages/client/src/pages/note-history.vue @@ -4,30 +4,35 @@ > - - -
- - - -
-
+ +
+ + +
+ + + +
+
+
@@ -42,6 +47,7 @@ import XNote from "@/components/MkNote.vue"; import { i18n } from "@/i18n"; import { definePageMetadata } from "@/scripts/page-metadata"; import icon from "@/scripts/icon"; +import MkRemoteCaution from "@/components/MkRemoteCaution.vue"; const pagingComponent = ref>(); @@ -65,8 +71,7 @@ definePageMetadata( })), ); -const note = ref({} as entities.Note); -const loaded = ref(false); +const note = ref(null); onMounted(() => { api("notes/show", { @@ -79,20 +84,19 @@ onMounted(() => { res.replyId = null; note.value = res; - loaded.value = true; }); }); function convertNoteEditsToNotes(noteEdits: entities.NoteEdit[]) { const now: entities.NoteEdit = { id: "EditionNow", - noteId: note.value.id, - updatedAt: note.value.createdAt, - text: note.value.text, - cw: note.value.cw, - files: note.value.files, - fileIds: note.value.fileIds, - emojis: note.value.emojis, + noteId: note.value!.id, + updatedAt: note.value!.createdAt, + text: note.value!.text, + cw: note.value!.cw, + files: note.value!.files, + fileIds: note.value!.fileIds, + emojis: note.value!.emojis, }; return [now] @@ -108,7 +112,7 @@ function convertNoteEditsToNotes(noteEdits: entities.NoteEdit[]) { _shouldInsertAd_: false, files: noteEdit.files, fileIds: noteEdit.fileIds, - emojis: note.value.emojis.concat(noteEdit.emojis), + emojis: note.value!.emojis.concat(noteEdit.emojis), }); }); } From 54d9916fecaab64a8b61ea59fe52e6a51ebcc97e Mon Sep 17 00:00:00 2001 From: Lhcfl Date: Sun, 14 Apr 2024 16:34:33 +0800 Subject: [PATCH 3/9] fix: rss feed no HTML --- packages/backend/src/server/web/feed.ts | 47 ++++++++++++++++++------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/packages/backend/src/server/web/feed.ts b/packages/backend/src/server/web/feed.ts index e6b09b4f4f..3b1b9d6fa5 100644 --- a/packages/backend/src/server/web/feed.ts +++ b/packages/backend/src/server/web/feed.ts @@ -2,7 +2,19 @@ import { Feed } from "feed"; import { In, IsNull } from "typeorm"; import config from "@/config/index.js"; import type { User } from "@/models/entities/user.js"; +import type { Note } from "@/models/entities/note.js"; import { Notes, DriveFiles, UserProfiles, Users } from "@/models/index.js"; +import getNoteHtml from "@/remote/activitypub/misc/get-note-html.js"; + +/** + * If there is this part in the note, it will cause CDATA to be terminated early. + * So I inserted two zero-width spaces in the middle, which doesn't make a visual difference + * Although this is not a good solution, there seems no other way. + * Anyway, it is not common to encounter such extreme situations. + */ +function escapeCDATA(str: string) { + return str.replaceAll("]]>", "]​]​>"); +} export default async function ( user: User, @@ -15,7 +27,7 @@ export default async function ( const author = { link: `${config.url}/@${user.username}`, email: `${user.username}@${config.host}`, - name: user.name || user.username, + name: escapeCDATA(user.name || user.username), }; const profile = await UserProfiles.findOneByOrFail({ userId: user.id }); @@ -44,11 +56,13 @@ export default async function ( title: `${author.name} (@${user.username}@${config.host})`, updated: notes[0].createdAt, generator: "Firefish", - description: `${user.notesCount} Notes, ${ - profile.ffVisibility === "public" ? user.followingCount : "?" - } Following, ${ - profile.ffVisibility === "public" ? user.followersCount : "?" - } Followers${profile.description ? ` · ${profile.description}` : ""}`, + description: escapeCDATA( + `${user.notesCount} Notes, ${ + profile.ffVisibility === "public" ? user.followingCount : "?" + } Following, ${ + profile.ffVisibility === "public" ? user.followersCount : "?" + } Followers${profile.description ? ` · ${profile.description}` : ""}`, + ), link: author.link, image: await Users.getAvatarUrl(user), feedLinks: { @@ -88,19 +102,23 @@ export default async function ( } feed.addItem({ - title: title - .replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "") - .substring(0, 100), + title: escapeCDATA( + title + .replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "") + .substring(0, 100), + ), link: `${config.url}/notes/${note.id}`, date: note.createdAt, description: note.cw - ? note.cw.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "") + ? escapeCDATA(note.cw.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "")) : undefined, - content: contentStr.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, ""), + content: escapeCDATA( + contentStr.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, ""), + ), }); } - async function noteToString(note, isTheNote = false) { + async function noteToString(note: Note, isTheNote = false) { const author = isTheNote ? null : await Users.findOneBy({ id: note.userId }); @@ -135,7 +153,10 @@ export default async function ( }">${file.name}`; } } - outstr += `${note.cw ? note.cw + "
" : ""}${note.text || ""}${fileEle}`; + + outstr += `${note.cw ? note.cw + "
" : ""}${ + getNoteHtml(note) || "" + }${fileEle}`; if (isTheNote) { outstr += ` Date: Sun, 14 Apr 2024 16:44:12 +0800 Subject: [PATCH 4/9] fix: use better `]]>` replacer --- packages/backend/src/server/web/feed.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/backend/src/server/web/feed.ts b/packages/backend/src/server/web/feed.ts index 3b1b9d6fa5..f3b3c97c32 100644 --- a/packages/backend/src/server/web/feed.ts +++ b/packages/backend/src/server/web/feed.ts @@ -8,12 +8,9 @@ import getNoteHtml from "@/remote/activitypub/misc/get-note-html.js"; /** * If there is this part in the note, it will cause CDATA to be terminated early. - * So I inserted two zero-width spaces in the middle, which doesn't make a visual difference - * Although this is not a good solution, there seems no other way. - * Anyway, it is not common to encounter such extreme situations. */ function escapeCDATA(str: string) { - return str.replaceAll("]]>", "]​]​>"); + return str.replaceAll("]]>", "]]]]>"); } export default async function ( From ce672f4edd542d78a1b33429d379ec969ae163cb Mon Sep 17 00:00:00 2001 From: naskya Date: Sun, 21 Apr 2024 22:36:05 +0900 Subject: [PATCH 5/9] dev: add cargo test to pnpm scripts mocha test has been unmaintained for a long time and is very broken :( --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index a62fae09f0..93594a5698 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,9 @@ "debug": "pnpm run build:debug && pnpm run start", "build:debug": "pnpm run clean && pnpm node ./scripts/dev-build.mjs && pnpm run gulp", "mocha": "pnpm --filter backend run mocha", - "test": "pnpm run mocha", + "test": "pnpm run test:ts && pnpm run test:rs", + "test:ts": "pnpm run mocha", + "test:rs": "cargo test", "format": "pnpm run format:ts; pnpm run format:rs", "format:ts": "pnpm -r --parallel run format", "format:rs": "cargo fmt --all --", From a107d8c1ec8309ca9d76583acdcf2d072fda3bfc Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 22 Apr 2024 05:52:56 +0900 Subject: [PATCH 6/9] fix (backend): update import --- packages/backend/src/server/api/endpoints/antennas/create.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/antennas/create.ts b/packages/backend/src/server/api/endpoints/antennas/create.ts index 792c5e30b4..aa5dcee044 100644 --- a/packages/backend/src/server/api/endpoints/antennas/create.ts +++ b/packages/backend/src/server/api/endpoints/antennas/create.ts @@ -1,9 +1,8 @@ import define from "@/server/api/define.js"; -import { genId } from "backend-rs"; +import { fetchMeta, genId } from "backend-rs"; import { Antennas, UserLists, UserGroupJoinings } from "@/models/index.js"; import { ApiError } from "@/server/api/error.js"; import { publishInternalEvent } from "@/services/stream.js"; -import { fetchMeta } from "@/misc/fetch-meta.js"; export const meta = { tags: ["antennas"], From c4658801aa98e61f5ee14177583cc758c1904f1d Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 22 Apr 2024 05:54:32 +0900 Subject: [PATCH 7/9] chore: regenerate entities --- packages/backend-rs/src/model/entity/meta.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend-rs/src/model/entity/meta.rs b/packages/backend-rs/src/model/entity/meta.rs index 7d0972b844..fcba9e0be9 100644 --- a/packages/backend-rs/src/model/entity/meta.rs +++ b/packages/backend-rs/src/model/entity/meta.rs @@ -50,8 +50,6 @@ pub struct Model { pub local_drive_capacity_mb: i32, #[sea_orm(column_name = "remoteDriveCapacityMb")] pub remote_drive_capacity_mb: i32, - #[sea_orm(column_name = "antennaLimit")] - pub antenna_limit: i32, #[sea_orm(column_name = "summalyProxy")] pub summaly_proxy: Option, #[sea_orm(column_name = "enableEmail")] @@ -175,6 +173,8 @@ pub struct Model { pub more_urls: Json, #[sea_orm(column_name = "markLocalFilesNsfwByDefault")] pub mark_local_files_nsfw_by_default: bool, + #[sea_orm(column_name = "antennaLimit")] + pub antenna_limit: i32, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] From c9de5f6095dec1c3390a4e5c0300dd0fa296620a Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 22 Apr 2024 05:56:46 +0900 Subject: [PATCH 8/9] docs: update api-changes.md --- docs/api-change.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/api-change.md b/docs/api-change.md index f3ed584c32..dcd4329a27 100644 --- a/docs/api-change.md +++ b/docs/api-change.md @@ -2,6 +2,10 @@ Breaking changes are indicated by the :warning: icon. +## Unreleased + +- Added `antennaLimit` field to the response of `meta` and `admin/meta`, and the request of `admin/update-meta` (optional). + ## v20240413 - :warning: Removed `patrons` endpoint. From ebaefb9697f7705313ce477a1c6a7ed9ec71ad98 Mon Sep 17 00:00:00 2001 From: naskya Date: Mon, 22 Apr 2024 06:02:08 +0900 Subject: [PATCH 9/9] chore (minor, client): remove redundant attribute --- packages/client/src/pages/note-history.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/pages/note-history.vue b/packages/client/src/pages/note-history.vue index c3665d41bc..8c97448f72 100644 --- a/packages/client/src/pages/note-history.vue +++ b/packages/client/src/pages/note-history.vue @@ -5,7 +5,7 @@ /> -
+