Add public homepage subscribe endpoint for newsletter phone capture.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
ff291448f3
commit
88f6a430d9
@@ -0,0 +1,21 @@
|
|||||||
|
import { Transform } from 'class-transformer';
|
||||||
|
import { IsString, Matches } from 'class-validator';
|
||||||
|
|
||||||
|
const PERSIAN_DIGITS = '۰۱۲۳۴۵۶۷۸۹';
|
||||||
|
const ARABIC_DIGITS = '٠١٢٣٤٥٦٧٨٩';
|
||||||
|
|
||||||
|
export function normalizeCellNumber(value: unknown) {
|
||||||
|
if (typeof value !== 'string') return value;
|
||||||
|
return value
|
||||||
|
.trim()
|
||||||
|
.replace(/[۰-۹]/g, (digit) => String(PERSIAN_DIGITS.indexOf(digit)))
|
||||||
|
.replace(/[٠-٩]/g, (digit) => String(ARABIC_DIGITS.indexOf(digit)))
|
||||||
|
.replace(/[^\d]/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SubscribeDto {
|
||||||
|
@Transform(({ value }) => normalizeCellNumber(value))
|
||||||
|
@IsString()
|
||||||
|
@Matches(/^09\d{9}$/, { message: 'شماره موبایل معتبر نیست' })
|
||||||
|
cellNumber!: string;
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Controller, Get, Param, ParseIntPipe, Query } from '@nestjs/common';
|
import { Body, Controller, Get, Param, ParseIntPipe, Post, Query } from '@nestjs/common';
|
||||||
|
import { SubscribeDto } from './dto/subscribe.dto';
|
||||||
import { PublicService } from './public.service';
|
import { PublicService } from './public.service';
|
||||||
|
|
||||||
@Controller('public')
|
@Controller('public')
|
||||||
@@ -78,4 +79,9 @@ export class PublicController {
|
|||||||
listWebsiteSlots(@Query('storeSlug') storeSlug?: string) {
|
listWebsiteSlots(@Query('storeSlug') storeSlug?: string) {
|
||||||
return this.publicService.listWebsiteSlots(storeSlug);
|
return this.publicService.listWebsiteSlots(storeSlug);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Post('subscribe')
|
||||||
|
subscribe(@Body() dto: SubscribeDto) {
|
||||||
|
return this.publicService.subscribe(dto.cellNumber);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||||
import { Prisma, StoreStatus } from '@prisma/client';
|
import { Prisma, StoreStatus, UserRole } from '@prisma/client';
|
||||||
|
import * as bcrypt from 'bcrypt';
|
||||||
|
import { randomBytes } from 'crypto';
|
||||||
import { PrismaService } from '../prisma/prisma.service';
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
|
|
||||||
export type PublicCategoryTreeNode = {
|
export type PublicCategoryTreeNode = {
|
||||||
@@ -267,4 +269,39 @@ export class PublicService {
|
|||||||
|
|
||||||
return { storeSlug: store.slug, items };
|
return { storeSlug: store.slug, items };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async subscribe(cellNumber: string) {
|
||||||
|
const existing = await this.prisma.user.findUnique({
|
||||||
|
where: { cellNumber },
|
||||||
|
select: { id: true },
|
||||||
|
});
|
||||||
|
if (existing) {
|
||||||
|
return { ok: true as const, created: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
const passwordHash = await bcrypt.hash(randomBytes(32).toString('hex'), 10);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.prisma.user.create({
|
||||||
|
data: {
|
||||||
|
firstName: 'مشترک',
|
||||||
|
lastName: 'خبرنامه',
|
||||||
|
cellNumber,
|
||||||
|
passwordHash,
|
||||||
|
role: UserRole.CUSTOMER,
|
||||||
|
about: 'ثبتنام از پنجره اشتراک صفحه اصلی',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
if (
|
||||||
|
error instanceof Prisma.PrismaClientKnownRequestError &&
|
||||||
|
error.code === 'P2002'
|
||||||
|
) {
|
||||||
|
return { ok: true as const, created: false };
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { ok: true as const, created: true };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user