.
This commit is contained in:
@@ -0,0 +1 @@
|
||||
ALTER TABLE "Catalog" ADD COLUMN IF NOT EXISTS "imageUrl" TEXT;
|
||||
@@ -175,6 +175,7 @@ model Catalog {
|
||||
name String
|
||||
code String
|
||||
description String?
|
||||
imageUrl String?
|
||||
displayOrder Int @default(0)
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE "Catalog" ADD COLUMN IF NOT EXISTS "imageUrl" TEXT;
|
||||
@@ -175,6 +175,7 @@ model Catalog {
|
||||
name String
|
||||
code String
|
||||
description String?
|
||||
imageUrl String?
|
||||
displayOrder Int @default(0)
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
+4
-3
File diff suppressed because one or more lines are too long
+100
-5
File diff suppressed because one or more lines are too long
@@ -22,14 +22,6 @@ function mb(file) {
|
||||
return `${(statSync(file).size / (1024 * 1024)).toFixed(1)}MB`
|
||||
}
|
||||
|
||||
console.log('==> nest build')
|
||||
rmSync(path.join(root, 'dist'), { recursive: true, force: true })
|
||||
rmSync(path.join(root, 'tsconfig.build.tsbuildinfo'), { force: true })
|
||||
execSync('npx nest build', { stdio: 'inherit' })
|
||||
if (!existsSync(path.join(root, 'dist', 'main.js'))) {
|
||||
throw new Error('dist/main.js ساخته نشد')
|
||||
}
|
||||
|
||||
console.log('==> prisma generate (debian engine)')
|
||||
execSync('npx prisma generate', {
|
||||
stdio: 'inherit',
|
||||
@@ -44,6 +36,14 @@ if (!existsSync(engineSrc)) {
|
||||
throw new Error(`${engineName} ساخته نشد. binaryTargets را در schema.prisma چک کنید.`)
|
||||
}
|
||||
|
||||
console.log('==> nest build')
|
||||
rmSync(path.join(root, 'dist'), { recursive: true, force: true })
|
||||
rmSync(path.join(root, 'tsconfig.build.tsbuildinfo'), { force: true })
|
||||
execSync('npx nest build', { stdio: 'inherit' })
|
||||
if (!existsSync(path.join(root, 'dist', 'main.js'))) {
|
||||
throw new Error('dist/main.js ساخته نشد')
|
||||
}
|
||||
|
||||
rmSync(runtimeDir, { recursive: true, force: true })
|
||||
mkdirSync(runtimeDir, { recursive: true })
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
ConflictException,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
@@ -51,6 +52,7 @@ export class CatalogsService {
|
||||
name: dto.name.trim(),
|
||||
code: dto.code.trim(),
|
||||
description: dto.description?.trim() || null,
|
||||
imageUrl: this.normalizeImage(dto.imageUrl),
|
||||
displayOrder: dto.displayOrder ?? 0,
|
||||
isActive: dto.isActive ?? true,
|
||||
},
|
||||
@@ -83,6 +85,10 @@ export class CatalogsService {
|
||||
dto.description === undefined
|
||||
? undefined
|
||||
: dto.description?.trim() || null,
|
||||
imageUrl:
|
||||
dto.imageUrl === undefined
|
||||
? undefined
|
||||
: this.normalizeImage(dto.imageUrl),
|
||||
displayOrder: dto.displayOrder,
|
||||
isActive: dto.isActive,
|
||||
},
|
||||
@@ -122,12 +128,29 @@ export class CatalogsService {
|
||||
return catalog;
|
||||
}
|
||||
|
||||
private normalizeImage(value?: string | null) {
|
||||
if (value == null || value === '') return null;
|
||||
const image = value.trim();
|
||||
if (
|
||||
!image.startsWith('data:image/') &&
|
||||
!image.startsWith('https://') &&
|
||||
!image.startsWith('http://')
|
||||
) {
|
||||
throw new BadRequestException('فرمت تصویر کالیته نامعتبر است');
|
||||
}
|
||||
if (image.startsWith('data:image/') && image.length > 1_600_000) {
|
||||
throw new BadRequestException('حجم تصویر کالیته خیلی زیاد است');
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
private map(catalog: {
|
||||
id: string;
|
||||
companyId: string;
|
||||
name: string;
|
||||
code: string;
|
||||
description: string | null;
|
||||
imageUrl: string | null;
|
||||
displayOrder: number;
|
||||
isActive: boolean;
|
||||
createdAt: Date;
|
||||
@@ -142,6 +165,7 @@ export class CatalogsService {
|
||||
name: catalog.name,
|
||||
code: catalog.code,
|
||||
description: catalog.description ?? undefined,
|
||||
imageUrl: catalog.imageUrl ?? undefined,
|
||||
displayOrder: catalog.displayOrder,
|
||||
isActive: catalog.isActive,
|
||||
productCount: catalog._count.products,
|
||||
|
||||
@@ -31,6 +31,10 @@ export class CreateCatalogDto {
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
isActive?: boolean;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
imageUrl?: string | null;
|
||||
}
|
||||
|
||||
export class UpdateCatalogDto {
|
||||
@@ -56,6 +60,10 @@ export class UpdateCatalogDto {
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
isActive?: boolean;
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
imageUrl?: string | null;
|
||||
}
|
||||
|
||||
export class SetCatalogActiveDto {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Controller, Get } from '@nestjs/common';
|
||||
import { Public } from '../common/decorators/auth.decorators';
|
||||
import { SettingsService } from './settings.service';
|
||||
|
||||
@Controller('settings')
|
||||
export class PublicSettingsController {
|
||||
constructor(private readonly settingsService: SettingsService) {}
|
||||
|
||||
@Public()
|
||||
@Get('public')
|
||||
getPublic() {
|
||||
return this.settingsService.getPublicContact();
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { SettingsController } from './settings.controller';
|
||||
import { PublicSettingsController } from './public-settings.controller';
|
||||
import { SettingsService } from './settings.service';
|
||||
|
||||
@Module({
|
||||
controllers: [SettingsController],
|
||||
controllers: [SettingsController, PublicSettingsController],
|
||||
providers: [SettingsService],
|
||||
exports: [SettingsService],
|
||||
})
|
||||
|
||||
@@ -12,6 +12,14 @@ export class SettingsService {
|
||||
return this.map(settings);
|
||||
}
|
||||
|
||||
async getPublicContact() {
|
||||
const settings = await this.ensureDefaults();
|
||||
return {
|
||||
supportPhone: settings.supportPhone,
|
||||
supportEmail: settings.supportEmail,
|
||||
};
|
||||
}
|
||||
|
||||
async update(dto: UpdateSettingsDto) {
|
||||
await this.ensureDefaults();
|
||||
const settings = await this.prisma.systemSettings.update({
|
||||
|
||||
+14
-1
@@ -22,7 +22,20 @@ export class SmsService {
|
||||
const raw = (
|
||||
this.config.get<string>('SMS_ENABLED', 'true') ?? 'true'
|
||||
).toLowerCase();
|
||||
return raw === '1' || raw === 'true' || raw === 'yes';
|
||||
const flagOn = raw === '1' || raw === 'true' || raw === 'yes';
|
||||
if (!flagOn) return false;
|
||||
return this.hasUsableSecret();
|
||||
}
|
||||
|
||||
private hasUsableSecret(): boolean {
|
||||
const secretKey = this.config.get<string>('SMS_SECRET_KEY')?.trim() ?? '';
|
||||
if (!secretKey) return false;
|
||||
const placeholders = new Set([
|
||||
'your-sms-secret-key',
|
||||
'کلید-پیامک',
|
||||
'change-me',
|
||||
]);
|
||||
return !placeholders.has(secretKey);
|
||||
}
|
||||
|
||||
async send(to: string, message: string): Promise<SmsSendResult> {
|
||||
|
||||
Reference in New Issue
Block a user