manual auto-rotation

This commit is contained in:
iqubik
2026-03-28 23:46:42 +03:00
parent 9fdbde3cab
commit e7a63dfff0
13 changed files with 391 additions and 36 deletions
@@ -3,6 +3,7 @@ import {
IsArray,
ValidateNested,
IsOptional,
IsBoolean,
ArrayMinSize,
ArrayMaxSize,
} from 'class-validator';
@@ -35,4 +36,8 @@ export class CreateSubscriptionDto {
@ArrayMaxSize(20)
@IsOptional()
inboundsConfig?: InboundConfigDto[];
@IsBoolean()
@IsOptional()
isAutoRotationEnabled?: boolean;
}
@@ -0,0 +1,4 @@
import { PartialType } from '@nestjs/mapped-types';
import { CreateSubscriptionDto } from './create-subscription.dto';
export class UpdateSubscriptionDto extends PartialType(CreateSubscriptionDto) {}
@@ -22,6 +22,9 @@ export class Subscription {
@Column({ default: true })
isEnabled: boolean;
@Column({ default: true })
isAutoRotationEnabled: boolean;
@Column({ type: 'simple-json', nullable: true })
inboundsConfig: Array<{
type?: string;
@@ -6,9 +6,13 @@ import {
Body,
Param,
Put,
HttpCode,
HttpStatus,
NotFoundException,
} from '@nestjs/common';
import { SubscriptionsService } from './subscriptions.service';
import { CreateSubscriptionDto } from './dto/create-subscription.dto';
import { UpdateSubscriptionDto } from './dto/update-subscription.dto';
@Controller('subscriptions')
export class SubscriptionsController {
@@ -24,12 +28,63 @@ export class SubscriptionsController {
return this.subscriptionsService.create(createSubscriptionDto);
}
@Put(':id')
update(
@Param('id') id: string,
@Body() updateSubscriptionDto: CreateSubscriptionDto,
@Put('bulk-auto-rotation')
@HttpCode(HttpStatus.OK)
async bulkUpdateAutoRotation(
@Body() body: { subscriptionIds: string[]; enabled: boolean },
) {
return this.subscriptionsService.update(id, updateSubscriptionDto);
const { subscriptionIds, enabled } = body;
if (!Array.isArray(subscriptionIds)) {
return {
success: false,
message: 'subscriptionIds должен быть массивом',
};
}
if (subscriptionIds.length > 100) {
return {
success: false,
message: 'Максимум 100 ID за раз',
};
}
const updated: string[] = [];
const notFound: string[] = [];
for (const id of subscriptionIds) {
const result = await this.subscriptionsService.update(id, {
isAutoRotationEnabled: enabled,
});
if (result) {
updated.push(id);
} else {
notFound.push(id);
}
}
return {
success: true,
message: `Обновлено ${updated.length} подписок`,
updatedCount: updated.length,
notFound: notFound.length > 0 ? notFound : undefined,
};
}
@Put(':id')
async update(
@Param('id') id: string,
@Body() updateSubscriptionDto: UpdateSubscriptionDto,
) {
const result = await this.subscriptionsService.update(
id,
updateSubscriptionDto,
);
if (!result) {
throw new NotFoundException(`Подписка ${id} не найдена`);
}
return result;
}
@Delete(':id')
@@ -1,9 +1,10 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Subscription } from './entities/subscription.entity';
import { XuiService } from '../xui/xui.service';
import { CreateSubscriptionDto } from './dto/create-subscription.dto';
import { UpdateSubscriptionDto } from './dto/update-subscription.dto';
import { v4 as uuidv4 } from 'uuid';
@Injectable()
@@ -26,27 +27,35 @@ export class SubscriptionsService {
name: dto.name,
uuid: uuidv4(),
inboundsConfig: dto.inboundsConfig || [],
isAutoRotationEnabled: dto.isAutoRotationEnabled ?? true,
});
return this.subRepo.save(sub);
}
async update(id: string, dto: CreateSubscriptionDto) {
async update(id: string, dto: UpdateSubscriptionDto) {
const sub = await this.subRepo.findOne({
where: { id },
relations: ['inbounds'],
});
if (!sub) {
throw new NotFoundException(`Subscription with ID ${id} not found`);
return null;
}
sub.name = dto.name;
// Пустое имя не обновляется — защита от случайной очистки
if (dto.name && dto.name.trim().length > 0) {
sub.name = dto.name;
}
if (dto.inboundsConfig) {
sub.inboundsConfig = dto.inboundsConfig;
}
if (dto.isAutoRotationEnabled !== undefined) {
sub.isAutoRotationEnabled = dto.isAutoRotationEnabled;
}
return this.subRepo.save(sub);
}