Merge remote-tracking branch 'origin/master' into internal

This commit is contained in:
2026-03-19 01:55:01 -07:00
101 changed files with 6910 additions and 330 deletions
@@ -0,0 +1,28 @@
-- Purpose: Rollback node group management tables
-- Author: Tension
-- Date: 2025-02-23
-- Updated: 2025-03-06
-- ===== Remove system configuration entries =====
DELETE FROM `system` WHERE `category` = 'group' AND `key` IN ('enabled', 'mode', 'auto_create_group');
-- ===== Remove columns and indexes from subscribe table =====
ALTER TABLE `subscribe` DROP INDEX IF EXISTS `idx_node_group_id`;
ALTER TABLE `subscribe` DROP COLUMN IF EXISTS `node_group_id`;
ALTER TABLE `subscribe` DROP COLUMN IF EXISTS `node_group_ids`;
-- ===== Remove columns and indexes from user_subscribe table =====
ALTER TABLE `user_subscribe` DROP INDEX IF EXISTS `idx_node_group_id`;
ALTER TABLE `user_subscribe` DROP COLUMN IF EXISTS `node_group_id`;
-- ===== Remove columns and indexes from nodes table =====
ALTER TABLE `nodes` DROP COLUMN IF EXISTS `node_group_ids`;
-- ===== Drop group_history_detail table =====
DROP TABLE IF EXISTS `group_history_detail`;
-- ===== Drop group_history table =====
DROP TABLE IF EXISTS `group_history`;
-- ===== Drop node_group table =====
DROP TABLE IF EXISTS `node_group`;
@@ -0,0 +1,130 @@
-- Purpose: Add node group management tables with multi-group support
-- Author: Tension
-- Date: 2025-02-23
-- Updated: 2025-03-06
-- ===== Create node_group table =====
DROP TABLE IF EXISTS `node_group`;
CREATE TABLE IF NOT EXISTS `node_group` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Name',
`description` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'Group Description',
`sort` int NOT NULL DEFAULT '0' COMMENT 'Sort Order',
`for_calculation` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'For Grouping Calculation: 0=false, 1=true',
`min_traffic_gb` bigint DEFAULT 0 COMMENT 'Minimum Traffic (GB) for this node group',
`max_traffic_gb` bigint DEFAULT 0 COMMENT 'Maximum Traffic (GB) for this node group',
`created_at` datetime(3) DEFAULT NULL COMMENT 'Create Time',
`updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time',
PRIMARY KEY (`id`),
KEY `idx_sort` (`sort`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='Node Groups';
-- ===== Create group_history table =====
DROP TABLE IF EXISTS `group_history`;
CREATE TABLE IF NOT EXISTS `group_history` (
`id` bigint NOT NULL AUTO_INCREMENT,
`group_mode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Group Mode: average/subscribe/traffic',
`trigger_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Trigger Type: manual/auto/schedule',
`state` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'State: pending/running/completed/failed',
`total_users` int NOT NULL DEFAULT '0' COMMENT 'Total Users',
`success_count` int NOT NULL DEFAULT '0' COMMENT 'Success Count',
`failed_count` int NOT NULL DEFAULT '0' COMMENT 'Failed Count',
`start_time` datetime(3) DEFAULT NULL COMMENT 'Start Time',
`end_time` datetime(3) DEFAULT NULL COMMENT 'End Time',
`operator` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'Operator',
`error_message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'Error Message',
`created_at` datetime(3) DEFAULT NULL COMMENT 'Create Time',
PRIMARY KEY (`id`),
KEY `idx_group_mode` (`group_mode`),
KEY `idx_trigger_type` (`trigger_type`),
KEY `idx_state` (`state`),
KEY `idx_created_at` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='Group Calculation History';
-- ===== Create group_history_detail table =====
-- Note: user_group_id column removed, using user_data JSON field instead
DROP TABLE IF EXISTS `group_history_detail`;
CREATE TABLE IF NOT EXISTS `group_history_detail` (
`id` bigint NOT NULL AUTO_INCREMENT,
`history_id` bigint NOT NULL COMMENT 'History ID',
`node_group_id` bigint NOT NULL COMMENT 'Node Group ID',
`user_count` int NOT NULL DEFAULT '0' COMMENT 'User Count',
`node_count` int NOT NULL DEFAULT '0' COMMENT 'Node Count',
`user_data` TEXT COMMENT 'User data JSON (id and email/phone)',
`created_at` datetime(3) DEFAULT NULL COMMENT 'Create Time',
PRIMARY KEY (`id`),
KEY `idx_history_id` (`history_id`),
KEY `idx_node_group_id` (`node_group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='Group History Details';
-- ===== Add columns to nodes table =====
SET @column_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'nodes' AND COLUMN_NAME = 'node_group_ids');
SET @sql = IF(@column_exists = 0,
'ALTER TABLE `nodes` ADD COLUMN `node_group_ids` JSON COMMENT ''Node Group IDs (JSON array, multiple groups)''',
'SELECT ''Column node_group_ids already exists''');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ===== Add node_group_id column to user_subscribe table =====
SET @column_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'user_subscribe' AND COLUMN_NAME = 'node_group_id');
SET @sql = IF(@column_exists = 0,
'ALTER TABLE `user_subscribe` ADD COLUMN `node_group_id` bigint NOT NULL DEFAULT 0 COMMENT ''Node Group ID (single ID)''',
'SELECT ''Column node_group_id already exists''');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ===== Add index for user_subscribe.node_group_id =====
SET @index_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'user_subscribe' AND INDEX_NAME = 'idx_node_group_id');
SET @sql = IF(@index_exists = 0,
'ALTER TABLE `user_subscribe` ADD INDEX `idx_node_group_id` (`node_group_id`)',
'SELECT ''Index idx_node_group_id already exists''');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ===== Add group_locked column to user_subscribe table =====
SET @column_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'user_subscribe' AND COLUMN_NAME = 'group_locked');
SET @sql = IF(@column_exists = 0,
'ALTER TABLE `user_subscribe` ADD COLUMN `group_locked` tinyint(1) NOT NULL DEFAULT 0 COMMENT ''Group Locked''',
'SELECT ''Column group_locked already exists in user_subscribe table''');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ===== Add columns to subscribe table =====
SET @column_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'subscribe' AND COLUMN_NAME = 'node_group_ids');
SET @sql = IF(@column_exists = 0,
'ALTER TABLE `subscribe` ADD COLUMN `node_group_ids` JSON COMMENT ''Node Group IDs (JSON array, multiple groups)''',
'SELECT ''Column node_group_ids already exists''');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ===== Add default node_group_id column to subscribe table =====
SET @column_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'subscribe' AND COLUMN_NAME = 'node_group_id');
SET @sql = IF(@column_exists = 0,
'ALTER TABLE `subscribe` ADD COLUMN `node_group_id` bigint NOT NULL DEFAULT 0 COMMENT ''Default Node Group ID (single ID)''',
'SELECT ''Column node_group_id already exists in subscribe table''');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ===== Add index for subscribe.node_group_id =====
SET @index_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'subscribe' AND INDEX_NAME = 'idx_node_group_id');
SET @sql = IF(@index_exists = 0,
'ALTER TABLE `subscribe` ADD INDEX `idx_node_group_id` (`node_group_id`)',
'SELECT ''Index idx_node_group_id already exists in subscribe table''');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ===== Insert system configuration entries =====
INSERT INTO `system` (`category`, `key`, `value`, `desc`) VALUES
('group', 'enabled', 'false', 'Group Management Enabled'),
('group', 'mode', 'average', 'Group Mode: average/subscribe/traffic'),
('group', 'auto_create_group', 'false', 'Auto-create user group when creating subscribe product')
ON DUPLICATE KEY UPDATE
`value` = VALUES(`value`),
`desc` = VALUES(`desc`);
@@ -0,0 +1,17 @@
-- Rollback: restore old verify configuration fields
INSERT INTO `system` (`category`, `key`, `value`, `type`, `desc`) VALUES
('verify', 'EnableLoginVerify', 'false', 'bool', 'is enable login verify'),
('verify', 'EnableRegisterVerify', 'false', 'bool', 'is enable register verify'),
('verify', 'EnableResetPasswordVerify', 'false', 'bool', 'is enable reset password verify')
ON DUPLICATE KEY UPDATE
`value` = VALUES(`value`),
`desc` = VALUES(`desc`);
-- Remove new captcha configuration fields
DELETE FROM `system` WHERE `category` = 'verify' AND `key` IN (
'CaptchaType',
'EnableUserLoginCaptcha',
'EnableUserRegisterCaptcha',
'EnableAdminLoginCaptcha',
'EnableUserResetPasswordCaptcha'
);
@@ -0,0 +1,17 @@
-- Add new captcha configuration fields
INSERT INTO `system` (`category`, `key`, `value`, `type`, `desc`) VALUES
('verify', 'CaptchaType', 'local', 'string', 'Captcha type: local or turnstile'),
('verify', 'EnableUserLoginCaptcha', 'false', 'bool', 'Enable captcha for user login'),
('verify', 'EnableUserRegisterCaptcha', 'false', 'bool', 'Enable captcha for user registration'),
('verify', 'EnableAdminLoginCaptcha', 'false', 'bool', 'Enable captcha for admin login'),
('verify', 'EnableUserResetPasswordCaptcha', 'false', 'bool', 'Enable captcha for user reset password')
ON DUPLICATE KEY UPDATE
`value` = VALUES(`value`),
`desc` = VALUES(`desc`);
-- Remove old verify configuration fields
DELETE FROM `system` WHERE `category` = 'verify' AND `key` IN (
'EnableLoginVerify',
'EnableRegisterVerify',
'EnableResetPasswordVerify'
);
@@ -0,0 +1,12 @@
-- 回滚 user_subscribe 表的过期流量字段
ALTER TABLE `user_subscribe`
DROP COLUMN `expired_upload`,
DROP COLUMN `expired_download`;
-- 回滚 node_group 表的过期节点组字段
ALTER TABLE `node_group`
DROP INDEX `idx_is_expired_group`,
DROP COLUMN `speed_limit`,
DROP COLUMN `max_traffic_gb_expired`,
DROP COLUMN `expired_days_limit`,
DROP COLUMN `is_expired_group`;
@@ -0,0 +1,14 @@
-- 为 node_group 表添加过期节点组相关字段
ALTER TABLE `node_group`
ADD COLUMN `is_expired_group` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Is Expired Group: 0=normal, 1=expired group' AFTER `for_calculation`,
ADD COLUMN `expired_days_limit` int NOT NULL DEFAULT 7 COMMENT 'Expired days limit (days)' AFTER `is_expired_group`,
ADD COLUMN `max_traffic_gb_expired` bigint DEFAULT 0 COMMENT 'Max traffic for expired users (GB)' AFTER `expired_days_limit`,
ADD COLUMN `speed_limit` int NOT NULL DEFAULT 0 COMMENT 'Speed limit (KB/s)' AFTER `max_traffic_gb_expired`;
-- 添加索引
ALTER TABLE `node_group` ADD INDEX `idx_is_expired_group` (`is_expired_group`);
-- 为 user_subscribe 表添加过期流量统计字段
ALTER TABLE `user_subscribe`
ADD COLUMN `expired_download` bigint NOT NULL DEFAULT 0 COMMENT 'Expired period download traffic (bytes)' AFTER `upload`,
ADD COLUMN `expired_upload` bigint NOT NULL DEFAULT 0 COMMENT 'Expired period upload traffic (bytes)' AFTER `expired_download`;
@@ -0,0 +1,6 @@
-- Purpose: Rollback traffic_limit rules from subscribe
-- Author: Claude Code
-- Date: 2026-03-12
-- ===== Remove traffic_limit column from subscribe table =====
ALTER TABLE `subscribe` DROP COLUMN IF EXISTS `traffic_limit`;
@@ -0,0 +1,22 @@
-- Purpose: Add traffic_limit rules to subscribe
-- Author: Claude Code
-- Date: 2026-03-12
-- ===== Add traffic_limit column to subscribe table =====
SET @column_exists = (
SELECT COUNT(*)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'subscribe'
AND COLUMN_NAME = 'traffic_limit'
);
SET @sql = IF(
@column_exists = 0,
'ALTER TABLE `subscribe` ADD COLUMN `traffic_limit` TEXT NULL COMMENT ''Traffic Limit Rules (JSON)'' AFTER `node_group_id`',
'SELECT ''Column traffic_limit already exists in subscribe table'''
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;