add new lagin desktop
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import {
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
Post,
|
||||
UploadedFile,
|
||||
UseGuards,
|
||||
UseInterceptors,
|
||||
} from '@nestjs/common';
|
||||
import { FileInterceptor } from '@nestjs/platform-express';
|
||||
import { memoryStorage } from 'multer';
|
||||
import { UserRole } from '../../entities/user.entity';
|
||||
import { Roles } from '../auth/decorators/roles.decorator';
|
||||
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
|
||||
import { RolesGuard } from '../auth/guards/roles.guard';
|
||||
import {
|
||||
PlatformSettingsDto,
|
||||
PlatformSettingsService,
|
||||
} from './platform-settings.service';
|
||||
|
||||
@Controller('platform-settings')
|
||||
export class PlatformSettingsController {
|
||||
constructor(private readonly service: PlatformSettingsService) {}
|
||||
|
||||
@Get()
|
||||
getSettings(): Promise<PlatformSettingsDto> {
|
||||
return this.service.getSettings();
|
||||
}
|
||||
|
||||
@Post('login-hero-image')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles(UserRole.ADMIN)
|
||||
@UseInterceptors(
|
||||
FileInterceptor('file', {
|
||||
storage: memoryStorage(),
|
||||
limits: { fileSize: 5 * 1024 * 1024 },
|
||||
}),
|
||||
)
|
||||
uploadLoginHeroImage(
|
||||
@UploadedFile() file: Express.Multer.File,
|
||||
): Promise<PlatformSettingsDto> {
|
||||
return this.service.uploadLoginHeroImage(file);
|
||||
}
|
||||
|
||||
@Delete('login-hero-image')
|
||||
@UseGuards(JwtAuthGuard, RolesGuard)
|
||||
@Roles(UserRole.ADMIN)
|
||||
removeLoginHeroImage(): Promise<PlatformSettingsDto> {
|
||||
return this.service.removeLoginHeroImage();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { PlatformSettingsEntity } from '../../entities/platform-settings.entity';
|
||||
import { AuthModule } from '../auth/auth.module';
|
||||
import { PlatformSettingsController } from './platform-settings.controller';
|
||||
import { PlatformSettingsService } from './platform-settings.service';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([PlatformSettingsEntity]), AuthModule],
|
||||
controllers: [PlatformSettingsController],
|
||||
providers: [PlatformSettingsService],
|
||||
exports: [PlatformSettingsService],
|
||||
})
|
||||
export class PlatformSettingsModule {}
|
||||
@@ -0,0 +1,112 @@
|
||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { randomUUID } from 'crypto';
|
||||
import { existsSync, mkdirSync, unlinkSync } from 'fs';
|
||||
import { extname, join } from 'path';
|
||||
import { Repository } from 'typeorm';
|
||||
import { PlatformSettingsEntity } from '../../entities/platform-settings.entity';
|
||||
|
||||
const ALLOWED_MIME = new Set([
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/webp',
|
||||
'image/gif',
|
||||
]);
|
||||
const MAX_FILE_BYTES = 5 * 1024 * 1024;
|
||||
const SETTINGS_ID = 1;
|
||||
|
||||
export type PlatformSettingsDto = {
|
||||
loginHeroImageUrl: string | null;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class PlatformSettingsService {
|
||||
private readonly uploadRoot: string;
|
||||
|
||||
constructor(
|
||||
@InjectRepository(PlatformSettingsEntity)
|
||||
private readonly repo: Repository<PlatformSettingsEntity>,
|
||||
) {
|
||||
this.uploadRoot = join(process.cwd(), process.env.UPLOAD_DIR ?? 'uploads');
|
||||
}
|
||||
|
||||
async getSettings(): Promise<PlatformSettingsDto> {
|
||||
const row = await this.ensureRow();
|
||||
return this.toDto(row);
|
||||
}
|
||||
|
||||
async uploadLoginHeroImage(
|
||||
file: Express.Multer.File,
|
||||
): Promise<PlatformSettingsDto> {
|
||||
this.validateFile(file);
|
||||
|
||||
const row = await this.ensureRow();
|
||||
const dir = join(this.uploadRoot, 'platform');
|
||||
mkdirSync(dir, { recursive: true });
|
||||
|
||||
if (row.loginHeroImageUrl) {
|
||||
this.deleteStoredFile(row.loginHeroImageUrl);
|
||||
}
|
||||
|
||||
const ext = extname(file.originalname).toLowerCase() || '.jpg';
|
||||
const filename = `login-hero-${randomUUID()}${ext}`;
|
||||
const relativeUrl = `platform/${filename}`;
|
||||
const absolutePath = join(this.uploadRoot, relativeUrl);
|
||||
|
||||
const { writeFileSync } = await import('fs');
|
||||
writeFileSync(absolutePath, file.buffer);
|
||||
|
||||
row.loginHeroImageUrl = relativeUrl;
|
||||
row.updatedAt = new Date();
|
||||
await this.repo.save(row);
|
||||
|
||||
return this.toDto(row);
|
||||
}
|
||||
|
||||
async removeLoginHeroImage(): Promise<PlatformSettingsDto> {
|
||||
const row = await this.ensureRow();
|
||||
|
||||
if (row.loginHeroImageUrl) {
|
||||
this.deleteStoredFile(row.loginHeroImageUrl);
|
||||
row.loginHeroImageUrl = null;
|
||||
row.updatedAt = new Date();
|
||||
await this.repo.save(row);
|
||||
}
|
||||
|
||||
return this.toDto(row);
|
||||
}
|
||||
|
||||
private async ensureRow(): Promise<PlatformSettingsEntity> {
|
||||
let row = await this.repo.findOne({ where: { id: SETTINGS_ID } });
|
||||
if (!row) {
|
||||
row = this.repo.create({ id: SETTINGS_ID, loginHeroImageUrl: null });
|
||||
await this.repo.save(row);
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
private toDto(row: PlatformSettingsEntity): PlatformSettingsDto {
|
||||
return {
|
||||
loginHeroImageUrl: row.loginHeroImageUrl,
|
||||
};
|
||||
}
|
||||
|
||||
private validateFile(file: Express.Multer.File | undefined): void {
|
||||
if (!file) {
|
||||
throw new BadRequestException('Image file is required');
|
||||
}
|
||||
if (!ALLOWED_MIME.has(file.mimetype)) {
|
||||
throw new BadRequestException('Only JPEG, PNG, WebP, and GIF images are allowed');
|
||||
}
|
||||
if (file.size > MAX_FILE_BYTES) {
|
||||
throw new BadRequestException('Image must be at most 5 MB');
|
||||
}
|
||||
}
|
||||
|
||||
private deleteStoredFile(relativeUrl: string): void {
|
||||
const absolutePath = join(this.uploadRoot, relativeUrl);
|
||||
if (existsSync(absolutePath)) {
|
||||
unlinkSync(absolutePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user