Compare commits

...

6 Commits

Author SHA1 Message Date
laozhoubuluo e922e88155 Merge branch 'feat/antenna_limit' into 'develop'
feat: antenna limit

Co-authored-by: naskya <m@naskya.net>

Closes #10894

See merge request firefish/firefish!10740
2024-04-21 20:57:36 +00:00
naskya c9de5f6095
docs: update api-changes.md 2024-04-22 05:56:46 +09:00
naskya c4658801aa
chore: regenerate entities 2024-04-22 05:54:32 +09:00
naskya a107d8c1ec
fix (backend): update import 2024-04-22 05:52:56 +09:00
naskya 4c91e8e37f
Merge branch 'develop' into feat/antenna_limit 2024-04-22 05:51:22 +09:00
老周部落 5eff4da27b
feat: antenna limit 2024-04-13 10:02:32 +08:00
13 changed files with 72 additions and 2 deletions

View File

@ -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.

View File

@ -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"

View File

@ -340,6 +340,7 @@ invite: "邀请"
driveCapacityPerLocalAccount: "每个本地用户的网盘容量"
driveCapacityPerRemoteAccount: "每个远程用户的网盘容量"
inMb: "以兆字节 (MegaByte) 为单位"
antennaLimit: "每个用户最多可以创建的天线数量"
iconUrl: "图标 URL"
bannerUrl: "横幅图 URL"
backgroundImageUrl: "背景图 URL"

View File

@ -492,6 +492,7 @@ export interface Meta {
recaptchaSecretKey: string | null
localDriveCapacityMb: number
remoteDriveCapacityMb: number
antennaLimit: number
summalyProxy: string | null
enableEmail: boolean
email: string | null

View File

@ -173,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)]

View File

@ -0,0 +1,19 @@
import type { MigrationInterface, QueryRunner } from "typeorm";
export class antennaLimit1712937600000 implements MigrationInterface {
async up(queryRunner: QueryRunner): Promise<void> {
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<void> {
await queryRunner.query(
`ALTER TABLE "meta" DROP COLUMN "antennaLimit"`,
undefined,
);
}
}

View File

@ -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,

View File

@ -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,

View File

@ -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;
}

View File

@ -1,5 +1,5 @@
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";
@ -109,10 +109,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);
}

View File

@ -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,

View File

@ -350,6 +350,19 @@
</FormSplit>
</FormSection>
<FormSection>
<template #label>{{ i18n.ts.antennas }}</template>
<FormInput
v-model="antennaLimit"
type="number"
class="_formBlock"
>
<template #label>{{
i18n.ts.antennaLimit
}}</template>
</FormInput>
</FormSection>
<FormSection>
<template #label>ServiceWorker</template>
@ -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,

View File

@ -356,6 +356,7 @@ export type LiteInstanceMetadata = {
disableGlobalTimeline: boolean;
driveCapacityPerLocalUserMb: number;
driveCapacityPerRemoteUserMb: number;
antennaLimit: number;
enableHcaptcha: boolean;
hcaptchaSiteKey: string | null;
enableRecaptcha: boolean;