feat(sub): allow identity tokens on every subscription link (#5935)

Keep usage tokens first-link-only while adding an opt-in setting for repeating EMAIL and USERNAME in subscription-body remarks.

Co-authored-by: x06579 <x06579@ai-dashboard>
This commit is contained in:
H-TTTTT
2026-07-29 04:12:52 +08:00
committed by GitHub
parent 8bbca76bdd
commit 8f49327efb
29 changed files with 190 additions and 9 deletions
+2
View File
@@ -75,6 +75,7 @@ export const EXAMPLES: Record<string, unknown> = {
"subPort": 1,
"subProfileUrl": "",
"subRoutingRules": "",
"subShowIdentityOnAllLinks": false,
"subSupportUrl": "",
"subThemeDir": "",
"subTitle": "",
@@ -186,6 +187,7 @@ export const EXAMPLES: Record<string, unknown> = {
"subPort": 1,
"subProfileUrl": "",
"subRoutingRules": "",
"subShowIdentityOnAllLinks": false,
"subSupportUrl": "",
"subThemeDir": "",
"subTitle": "",
+8
View File
@@ -244,6 +244,9 @@ export const SCHEMAS: Record<string, unknown> = {
"subRoutingRules": {
"type": "string"
},
"subShowIdentityOnAllLinks": {
"type": "boolean"
},
"subSupportUrl": {
"type": "string"
},
@@ -415,6 +418,7 @@ export const SCHEMAS: Record<string, unknown> = {
"subPort",
"subProfileUrl",
"subRoutingRules",
"subShowIdentityOnAllLinks",
"subSupportUrl",
"subThemeDir",
"subTitle",
@@ -711,6 +715,9 @@ export const SCHEMAS: Record<string, unknown> = {
"subRoutingRules": {
"type": "string"
},
"subShowIdentityOnAllLinks": {
"type": "boolean"
},
"subSupportUrl": {
"type": "string"
},
@@ -889,6 +896,7 @@ export const SCHEMAS: Record<string, unknown> = {
"subPort",
"subProfileUrl",
"subRoutingRules",
"subShowIdentityOnAllLinks",
"subSupportUrl",
"subThemeDir",
"subTitle",
+2
View File
@@ -81,6 +81,7 @@ export interface AllSetting {
subPort: number;
subProfileUrl: string;
subRoutingRules: string;
subShowIdentityOnAllLinks: boolean;
subSupportUrl: string;
subThemeDir: string;
subTitle: string;
@@ -193,6 +194,7 @@ export interface AllSettingView {
subPort: number;
subProfileUrl: string;
subRoutingRules: string;
subShowIdentityOnAllLinks: boolean;
subSupportUrl: string;
subThemeDir: string;
subTitle: string;
+2
View File
@@ -93,6 +93,7 @@ export const AllSettingSchema = z.object({
subPort: z.number().int().min(1).max(65535),
subProfileUrl: z.string(),
subRoutingRules: z.string(),
subShowIdentityOnAllLinks: z.boolean(),
subSupportUrl: z.string(),
subThemeDir: z.string(),
subTitle: z.string(),
@@ -206,6 +207,7 @@ export const AllSettingViewSchema = z.object({
subPort: z.number().int().min(1).max(65535),
subProfileUrl: z.string(),
subRoutingRules: z.string(),
subShowIdentityOnAllLinks: z.boolean(),
subSupportUrl: z.string(),
subThemeDir: z.string(),
subTitle: z.string(),
+1
View File
@@ -14,6 +14,7 @@ export class AllSetting {
expireDiff = 0;
trafficDiff = 0;
remarkTemplate = '{{INBOUND}}-{{EMAIL}}|📊{{TRAFFIC_LEFT}}|⏳{{DAYS_LEFT}}D';
subShowIdentityOnAllLinks = false;
datepicker: 'gregorian' | 'jalalian' = 'gregorian';
tgBotEnable = false;
tgBotToken = '';
@@ -93,6 +93,16 @@ export default function SubscriptionGeneralTab({ allSetting, updateSetting }: Su
maxLength={256}
/>
</SettingListItem>
<SettingListItem
paddings="small"
title={t('pages.settings.subShowIdentityOnAllLinks')}
description={t('pages.settings.subShowIdentityOnAllLinksDesc')}
>
<Switch
checked={allSetting.subShowIdentityOnAllLinks}
onChange={(v) => updateSetting({ subShowIdentityOnAllLinks: v })}
/>
</SettingListItem>
<SettingListItem paddings="small" title={t('pages.settings.subUpdates')} description={t('pages.settings.subUpdatesDesc')}>
<InputNumber value={allSetting.subUpdates} min={0} max={525600} style={{ width: '100%' }}
+1
View File
@@ -18,6 +18,7 @@ export const AllSettingSchema = z.object({
expireDiff: nonNegativeInt.optional(),
trafficDiff: nonNegativeInt.max(100).optional(),
remarkTemplate: z.string().optional(),
subShowIdentityOnAllLinks: z.boolean().optional(),
datepicker: z.enum(['gregorian', 'jalalian']).optional(),
tgBotEnable: z.boolean().optional(),
tgBotToken: z.string().optional(),
@@ -0,0 +1,22 @@
import { describe, it, expect } from 'vitest';
import { AllSettingSchema } from '@/schemas/setting';
import { AllSetting } from '@/models/setting';
describe('subShowIdentityOnAllLinks', () => {
it('defaults to false on AllSetting', () => {
expect(new AllSetting().subShowIdentityOnAllLinks).toBe(false);
});
it('accepts boolean values in the settings schema', () => {
for (const v of [true, false]) {
const r = AllSettingSchema.safeParse({ subShowIdentityOnAllLinks: v });
expect(r.success, `subShowIdentityOnAllLinks=${v}`).toBe(true);
}
});
it('rejects non-boolean values', () => {
for (const v of ['true', 1, null]) {
expect(AllSettingSchema.safeParse({ subShowIdentityOnAllLinks: v }).success).toBe(false);
}
});
});