171 lines
5.4 KiB
TypeScript
171 lines
5.4 KiB
TypeScript
import {
|
|
Controller, Get, Post, Put, Patch, Delete, Inject,
|
|
Param, Query, Body, UseGuards, UseInterceptors, UploadedFile, Req,
|
|
} from '@nestjs/common';
|
|
import { FileInterceptor } from '@nestjs/platform-express';
|
|
import { ApiTags, ApiOperation, ApiBearerAuth, ApiConsumes } from '@nestjs/swagger';
|
|
import { JwtAuthGuard, Roles, RolesGuard, UserRole } from '@genex/common';
|
|
import { AppVersionService } from '../../../application/services/app-version.service';
|
|
import { FileStorageService } from '../../../application/services/file-storage.service';
|
|
import { PACKAGE_PARSER, IPackageParser } from '../../../domain/ports/package-parser.interface';
|
|
import { Platform } from '../../../domain/enums/platform.enum';
|
|
|
|
@ApiTags('admin-versions')
|
|
@Controller('admin/versions')
|
|
@UseGuards(JwtAuthGuard, RolesGuard)
|
|
@Roles(UserRole.ADMIN)
|
|
@ApiBearerAuth()
|
|
export class AdminVersionController {
|
|
constructor(
|
|
private readonly versionService: AppVersionService,
|
|
private readonly fileStorage: FileStorageService,
|
|
@Inject(PACKAGE_PARSER) private readonly packageParser: IPackageParser,
|
|
) {}
|
|
|
|
@Get()
|
|
@ApiOperation({ summary: 'List app versions' })
|
|
async listVersions(
|
|
@Query('platform') platform?: string,
|
|
@Query('includeDisabled') includeDisabled?: string,
|
|
) {
|
|
const platformEnum = platform
|
|
? (platform.toUpperCase() as Platform)
|
|
: undefined;
|
|
const versions = await this.versionService.listVersions(
|
|
platformEnum,
|
|
includeDisabled === 'true',
|
|
);
|
|
return { code: 0, data: versions };
|
|
}
|
|
|
|
@Get(':id')
|
|
@ApiOperation({ summary: 'Get version details' })
|
|
async getVersion(@Param('id') id: string) {
|
|
const version = await this.versionService.getVersion(id);
|
|
return { code: 0, data: version };
|
|
}
|
|
|
|
@Post()
|
|
@ApiOperation({ summary: 'Create version manually' })
|
|
async createVersion(
|
|
@Body() body: {
|
|
platform: string;
|
|
versionCode: number;
|
|
versionName: string;
|
|
buildNumber: string;
|
|
downloadUrl: string;
|
|
fileSize: string;
|
|
fileSha256: string;
|
|
changelog: string;
|
|
isForceUpdate: boolean;
|
|
minOsVersion?: string;
|
|
releaseDate?: string;
|
|
},
|
|
@Req() req: any,
|
|
) {
|
|
const version = await this.versionService.createVersion({
|
|
...body,
|
|
platform: body.platform.toUpperCase() as Platform,
|
|
releaseDate: body.releaseDate ? new Date(body.releaseDate) : undefined,
|
|
createdBy: req.user?.sub,
|
|
});
|
|
return { code: 0, data: version };
|
|
}
|
|
|
|
@Post('upload')
|
|
@UseInterceptors(FileInterceptor('file'))
|
|
@ApiConsumes('multipart/form-data')
|
|
@ApiOperation({ summary: 'Upload APK/IPA and create version' })
|
|
async uploadVersion(
|
|
@UploadedFile() file: Express.Multer.File,
|
|
@Body() body: {
|
|
platform: string;
|
|
versionCode?: string;
|
|
versionName?: string;
|
|
buildNumber?: string;
|
|
changelog?: string;
|
|
isForceUpdate?: string;
|
|
minOsVersion?: string;
|
|
releaseDate?: string;
|
|
},
|
|
@Req() req: any,
|
|
) {
|
|
// Parse package to extract metadata (auto-fill when not provided)
|
|
const parsedInfo = await this.packageParser.parse(file.buffer, file.originalname);
|
|
|
|
const platform: Platform = body.platform
|
|
? (body.platform.toUpperCase() as Platform)
|
|
: (parsedInfo.platform as Platform);
|
|
const versionCode = body.versionCode
|
|
? parseInt(body.versionCode, 10)
|
|
: parsedInfo.versionCode || Date.now();
|
|
const versionName = body.versionName || parsedInfo.versionName || '1.0.0';
|
|
const buildNumber = body.buildNumber || versionCode.toString();
|
|
|
|
// Upload to MinIO
|
|
const uploadResult = await this.fileStorage.uploadFile(
|
|
file.buffer,
|
|
file.originalname,
|
|
platform,
|
|
versionName,
|
|
);
|
|
|
|
const version = await this.versionService.createVersion({
|
|
platform,
|
|
versionCode,
|
|
versionName,
|
|
buildNumber,
|
|
downloadUrl: uploadResult.downloadUrl,
|
|
fileSize: uploadResult.fileSize,
|
|
fileSha256: uploadResult.sha256,
|
|
changelog: body.changelog || '',
|
|
isForceUpdate: body.isForceUpdate === 'true',
|
|
minOsVersion: body.minOsVersion || parsedInfo.minSdkVersion,
|
|
releaseDate: body.releaseDate ? new Date(body.releaseDate) : undefined,
|
|
createdBy: req.user?.sub,
|
|
});
|
|
|
|
return { code: 0, data: version };
|
|
}
|
|
|
|
@Post('parse')
|
|
@UseInterceptors(FileInterceptor('file'))
|
|
@ApiConsumes('multipart/form-data')
|
|
@ApiOperation({ summary: 'Parse APK/IPA without saving (preview metadata)' })
|
|
async parsePackage(@UploadedFile() file: Express.Multer.File) {
|
|
const info = await this.packageParser.parse(file.buffer, file.originalname);
|
|
return { code: 0, data: info };
|
|
}
|
|
|
|
@Put(':id')
|
|
@ApiOperation({ summary: 'Update version' })
|
|
async updateVersion(
|
|
@Param('id') id: string,
|
|
@Body() body: any,
|
|
@Req() req: any,
|
|
) {
|
|
const version = await this.versionService.updateVersion(id, {
|
|
...body,
|
|
updatedBy: req.user?.sub,
|
|
});
|
|
return { code: 0, data: version };
|
|
}
|
|
|
|
@Patch(':id/toggle')
|
|
@ApiOperation({ summary: 'Enable/disable version' })
|
|
async toggleVersion(
|
|
@Param('id') id: string,
|
|
@Body() body: { isEnabled: boolean },
|
|
) {
|
|
const result = await this.versionService.toggleVersion(id, body.isEnabled);
|
|
return { code: 0, data: result };
|
|
}
|
|
|
|
@Delete(':id')
|
|
@ApiOperation({ summary: 'Delete version' })
|
|
async deleteVersion(@Param('id') id: string) {
|
|
const result = await this.versionService.deleteVersion(id);
|
|
return { code: 0, data: result };
|
|
}
|
|
}
|