feat: Complete NestJS backend scaffold — 22 modules, 39 entities, WebSocket gateway
All checks were successful
Test Asgard Runner / test (push) Successful in 3s
All checks were successful
Test Asgard Runner / test (push) Successful in 3s
Full backend rewrite from Rust/Axum to NestJS/TypeScript. - 22 feature modules (auth, servers, wipes, maps, plugins, players, console, chat, team, notifications, settings, schedules, analytics, alerts, status, store, webstore, admin, setup, migration, users, licenses) - 39 TypeORM entities matching PostgreSQL schema (12 migrations) - Common infrastructure: JWT/RBAC guards, decorators, exception filter - NATS service with pub/sub/request-reply - Socket.IO WebSocket gateway with NATS bridge - Docker: NestJS Dockerfile + updated docker-compose.yml - Zero compile errors (npx tsc --noEmit clean) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
130
backend-nest/src/modules/wipes/wipes.service.ts
Normal file
130
backend-nest/src/modules/wipes/wipes.service.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { WipeProfile } from '../../entities/wipe-profile.entity';
|
||||
import { WipeSchedule } from '../../entities/wipe-schedule.entity';
|
||||
import { WipeHistory } from '../../entities/wipe-history.entity';
|
||||
import { CreateProfileDto } from './dto/create-profile.dto';
|
||||
import { UpdateProfileDto } from './dto/update-profile.dto';
|
||||
import { CreateScheduleDto } from './dto/create-schedule.dto';
|
||||
import { TriggerWipeDto } from './dto/trigger-wipe.dto';
|
||||
|
||||
@Injectable()
|
||||
export class WipesService {
|
||||
constructor(
|
||||
@InjectRepository(WipeProfile)
|
||||
private readonly wipeProfileRepo: Repository<WipeProfile>,
|
||||
@InjectRepository(WipeSchedule)
|
||||
private readonly wipeScheduleRepo: Repository<WipeSchedule>,
|
||||
@InjectRepository(WipeHistory)
|
||||
private readonly wipeHistoryRepo: Repository<WipeHistory>,
|
||||
) {}
|
||||
|
||||
async getProfiles(licenseId: string): Promise<WipeProfile[]> {
|
||||
return this.wipeProfileRepo.find({
|
||||
where: { license_id: licenseId },
|
||||
order: { created_at: 'DESC' },
|
||||
});
|
||||
}
|
||||
|
||||
async createProfile(licenseId: string, dto: CreateProfileDto): Promise<WipeProfile> {
|
||||
const profile = this.wipeProfileRepo.create({
|
||||
license_id: licenseId,
|
||||
...dto,
|
||||
});
|
||||
return this.wipeProfileRepo.save(profile);
|
||||
}
|
||||
|
||||
async updateProfile(
|
||||
licenseId: string,
|
||||
profileId: string,
|
||||
dto: UpdateProfileDto,
|
||||
): Promise<WipeProfile> {
|
||||
const profile = await this.wipeProfileRepo.findOne({
|
||||
where: { id: profileId, license_id: licenseId },
|
||||
});
|
||||
|
||||
if (!profile) {
|
||||
throw new NotFoundException(`Wipe profile ${profileId} not found`);
|
||||
}
|
||||
|
||||
Object.assign(profile, dto);
|
||||
profile.updated_at = new Date();
|
||||
return this.wipeProfileRepo.save(profile);
|
||||
}
|
||||
|
||||
async deleteProfile(licenseId: string, profileId: string): Promise<void> {
|
||||
const result = await this.wipeProfileRepo.delete({
|
||||
id: profileId,
|
||||
license_id: licenseId,
|
||||
});
|
||||
|
||||
if (result.affected === 0) {
|
||||
throw new NotFoundException(`Wipe profile ${profileId} not found`);
|
||||
}
|
||||
}
|
||||
|
||||
async getSchedules(licenseId: string): Promise<WipeSchedule[]> {
|
||||
return this.wipeScheduleRepo.find({
|
||||
where: { license_id: licenseId },
|
||||
relations: ['wipe_profile'],
|
||||
order: { created_at: 'DESC' },
|
||||
});
|
||||
}
|
||||
|
||||
async createSchedule(licenseId: string, dto: CreateScheduleDto): Promise<WipeSchedule> {
|
||||
const schedule = this.wipeScheduleRepo.create({
|
||||
license_id: licenseId,
|
||||
...dto,
|
||||
});
|
||||
return this.wipeScheduleRepo.save(schedule);
|
||||
}
|
||||
|
||||
async getHistory(licenseId: string, limit: number = 50): Promise<WipeHistory[]> {
|
||||
return this.wipeHistoryRepo.find({
|
||||
where: { license_id: licenseId },
|
||||
relations: ['wipe_profile', 'wipe_schedule', 'map'],
|
||||
order: { created_at: 'DESC' },
|
||||
take: limit,
|
||||
});
|
||||
}
|
||||
|
||||
async triggerWipe(
|
||||
licenseId: string,
|
||||
dto: TriggerWipeDto,
|
||||
): Promise<{ wipe_history_id: string }> {
|
||||
const history = this.wipeHistoryRepo.create({
|
||||
license_id: licenseId,
|
||||
wipe_type: dto.wipe_type,
|
||||
wipe_profile_id: dto.wipe_profile_id,
|
||||
trigger_type: 'manual',
|
||||
status: 'pending',
|
||||
});
|
||||
|
||||
const saved = await this.wipeHistoryRepo.save(history);
|
||||
return { wipe_history_id: saved.id };
|
||||
}
|
||||
|
||||
async triggerDryRun(
|
||||
licenseId: string,
|
||||
dto: TriggerWipeDto,
|
||||
): Promise<{
|
||||
would_delete: string[];
|
||||
would_preserve: string[];
|
||||
estimated_duration_seconds: number;
|
||||
}> {
|
||||
// Stub implementation - real logic would analyze wipe profile config
|
||||
const mockResult = {
|
||||
would_delete: ['*.sav', '*.db', 'player.deaths.db', 'player.identities.db'],
|
||||
would_preserve: ['oxide/', 'oxide/plugins/', 'oxide/data/', 'backups/'],
|
||||
estimated_duration_seconds: 45,
|
||||
};
|
||||
|
||||
if (dto.wipe_type === 'full') {
|
||||
mockResult.would_delete.push('oxide/data/*');
|
||||
mockResult.estimated_duration_seconds = 120;
|
||||
}
|
||||
|
||||
return mockResult;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user