chore: fix the purchased true for the danakservices

This commit is contained in:
mahyargdz
2025-08-31 11:36:57 +03:30
parent 8e9b939a0b
commit 787643a31f
8 changed files with 885 additions and 43 deletions
+7 -2
View File
@@ -4,8 +4,10 @@ import { connectionSource } from "./connection";
// import { seedAdmin } from "./seeders/admin.seeder";
// import { seedCityAndProvince } from "./seeders/iran-city.seeder";
// import { seedNotifSettings } from "./seeders/notif-setting.seeder";
import { seedPaymentGateways } from "./seeders/payment-gateway.seeder";
// import { seedPaymentGateways } from "./seeders/payment-gateway.seeder";
// import { seedPermissionsAndRoles } from "./seeders/role.seeder";
import { seedBlogCommentReplies } from "./seeders/blog-comment-reply.seeder";
import { seedBlogComments } from "./seeders/blog-comment.seeder";
const logger = new Logger("Seeder");
@@ -16,9 +18,12 @@ export const runSeeder = async () => {
// await seedPermissionsAndRoles(connectionSource, logger);
// await seedAdmin(connectionSource, logger);
// await seedNotifSettings(connectionSource, logger);
await seedPaymentGateways(connectionSource, logger);
// await seedPaymentGateways(connectionSource, logger);
// await seedCityAndProvince(connectionSource, logger);
await seedBlogComments(connectionSource, logger);
await seedBlogCommentReplies(connectionSource, logger);
logger.log("seeding completed");
process.exit(0);
};
@@ -0,0 +1,99 @@
import { Logger } from "@nestjs/common";
import { DataSource } from "typeorm";
import { BlogCommentReply } from "../../src/modules/blogs/entities/blog-comment-reply.entity";
import { BlogComment } from "../../src/modules/blogs/entities/blog-comment.entity";
import { User } from "../../src/modules/users/entities/user.entity";
const blogCommentReplies = [
{
content: "ممنون از نظر شما. خوشحالم که مقاله مفید بوده.",
isOfficialReply: true,
},
{
content: "بله، این روش در اکثر شرایط قابل استفاده است. فقط در موارد خاص نیاز به تنظیمات اضافی دارد.",
isOfficialReply: false,
},
{
content: "من هم همین تجربه را داشتم. واقعاً روش موثری است.",
isOfficialReply: false,
},
{
content: "در مقاله بعدی حتماً این بخش را بیشتر توضیح خواهم داد.",
isOfficialReply: true,
},
{
content: "خواهش می‌کنم. هدف ما کمک به کاربران است.",
isOfficialReply: true,
},
{
content: "پیشنهاد خوبی است. در نسخه بعدی مقاله حتماً مثال‌های بیشتری اضافه می‌کنم.",
isOfficialReply: true,
},
{
content: "متأسفم که این احساس را داشتید. سعی می‌کنم مطالب جدیدتری ارائه دهم.",
isOfficialReply: true,
},
{
content: "بله، حتماً. منابع علمی در انتهای مقاله آمده است.",
isOfficialReply: true,
},
{
content: "من هم همین سوال را داشتم. ممنون که پرسیدید.",
isOfficialReply: false,
},
{
content: "این روش را من هم امتحان کردم و نتیجه گرفتم.",
isOfficialReply: false,
},
{
content: "بله، کاملاً درست می‌گویید. این روش نیاز به تمرین دارد.",
isOfficialReply: false,
},
{
content: "من هم همین تجربه را داشتم. واقعاً عالی کار می‌کند.",
isOfficialReply: false,
},
];
export const seedBlogCommentReplies = async (dataSource: DataSource, logger: Logger) => {
try {
const replyRepo = dataSource.getRepository(BlogCommentReply);
const commentRepo = dataSource.getRepository(BlogComment);
const userRepo = dataSource.getRepository(User);
// Get existing comments and users
const comments = await commentRepo.find({ take: 10 });
const users = await userRepo.find({ take: 10 });
if (comments.length === 0) {
logger.warn("No blog comments found. Please seed blog comments first.");
return;
}
if (users.length === 0) {
logger.warn("No users found. Please seed users first.");
return;
}
for (const replyData of blogCommentReplies) {
// Randomly select comment and user
const randomComment = comments[Math.floor(Math.random() * comments.length)];
const randomUser = users[Math.floor(Math.random() * users.length)];
const reply = replyRepo.create({
...replyData,
comment: randomComment,
author: randomUser,
});
await replyRepo.save(reply);
logger.log(`Blog comment reply created successfully`);
}
logger.log("Blog comment replies seeding completed");
} catch (error) {
logger.error("Error in seeding blog comment replies", error);
process.exit(1);
}
};
+582
View File
@@ -0,0 +1,582 @@
import { Logger } from "@nestjs/common";
import { DataSource, IsNull } from "typeorm";
import { BlogComment } from "../../src/modules/blogs/entities/blog-comment.entity";
import { Blog } from "../../src/modules/blogs/entities/blog.entity";
import { CommentStatus } from "../../src/modules/blogs/enums/comment-status.enum";
import { User } from "../../src/modules/users/entities/user.entity";
const blogComments = [
{
title: "مقاله بسیار مفیدی بود",
content: "این مقاله اطلاعات بسیار ارزشمندی در اختیار من قرار داد. ممنون از نویسنده محترم که این مطالب مفید را گردآوری کرده است.",
status: CommentStatus.APPROVED,
},
{
title: "سوالی دارم",
content: "مطالب ارائه شده عالی بود اما یک سوال دارم: آیا این روش در تمام شرایط قابل استفاده است؟",
status: CommentStatus.APPROVED,
},
{
title: "تجربه شخصی",
content: "من این روش را امتحان کردم و نتایج فوق‌العاده‌ای گرفتم. پیشنهاد می‌کنم همه امتحان کنند.",
status: CommentStatus.APPROVED,
},
{
title: "نیاز به توضیح بیشتر",
content: "لطفاً در مورد بخش سوم مقاله توضیحات بیشتری ارائه دهید. این قسمت کمی مبهم است.",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از نویسنده",
content: "بسیار ممنون از زحمات شما. این مقاله کمک زیادی به من کرد.",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد بهبود",
content: "مقاله خوبی بود اما پیشنهاد می‌کنم مثال‌های بیشتری اضافه کنید تا درک بهتری حاصل شود.",
status: CommentStatus.APPROVED,
},
{
title: "مطالب تکراری",
content: "بخش‌هایی از این مقاله در مقالات قبلی هم آمده بود. بهتر است مطالب جدیدتری ارائه دهید.",
status: CommentStatus.REJECTED,
},
{
title: "سوال تخصصی",
content: "آیا می‌توانید منابع علمی این مقاله را هم معرفی کنید؟",
status: CommentStatus.APPROVED,
},
{
title: "عالی بود",
content: "واقعاً مقاله جامع و کاملی بود. همه چیز را به خوبی توضیح داده بودید.",
status: CommentStatus.APPROVED,
},
{
title: "مشکل در اجرا",
content: "من این روش را پیاده‌سازی کردم اما با مشکل مواجه شدم. لطفاً راهنمایی کنید.",
status: CommentStatus.APPROVED,
},
{
title: "نکته جالب",
content: "نکته جالبی در مورد بخش چهارم مقاله بود که قبلاً نمی‌دانستم.",
status: CommentStatus.APPROVED,
},
{
title: "درخواست مقاله جدید",
content: "لطفاً در مورد موضوع مشابه مقاله جدیدی بنویسید.",
status: CommentStatus.APPROVED,
},
{
title: "مقایسه با روش‌های دیگر",
content: "آیا می‌توانید این روش را با روش‌های مشابه مقایسه کنید؟",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد پیاده‌سازی",
content: "در مرحله سوم پیاده‌سازی، دقیقاً چه کاری باید انجام دهم؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر ویژه",
content: "بسیار ممنون از زحمات شما. این مقاله واقعاً کمک زیادی به من کرد.",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد موضوع",
content: "پیشنهاد می‌کنم در مورد موضوع X مقاله‌ای بنویسید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد کاربرد",
content: "آیا این روش در حوزه‌های دیگر هم قابل استفاده است؟",
status: CommentStatus.APPROVED,
},
{
title: "نیاز به مثال بیشتر",
content: "لطفاً مثال‌های عملی بیشتری اضافه کنید.",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از تیم",
content: "ممنون از تیم نویسندگان که این مطالب مفید را تهیه کرده‌اند.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد ابزارها",
content: "آیا ابزارهای خاصی برای این کار نیاز است؟",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد بهبود ساختار",
content: "پیشنهاد می‌کنم ساختار مقاله را کمی تغییر دهید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد زمان‌بندی",
content: "چقدر زمان برای پیاده‌سازی این روش نیاز است؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از توضیحات",
content: "توضیحات شما بسیار واضح و قابل فهم بود.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد هزینه",
content: "آیا این روش هزینه خاصی دارد؟",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد ویدیو",
content: "پیشنهاد می‌کنم ویدیوی آموزشی هم تهیه کنید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد محدودیت‌ها",
content: "آیا محدودیت خاصی در استفاده از این روش وجود دارد؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از پاسخ‌گویی",
content: "ممنون از پاسخ‌گویی سریع شما به سوالات.",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد کارگاه",
content: "پیشنهاد می‌کنم کارگاه آموزشی برگزار کنید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد پیش‌نیازها",
content: "چه پیش‌نیازهایی برای استفاده از این روش نیاز است؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از به‌روزرسانی",
content: "ممنون از به‌روزرسانی مداوم مقالات.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد پشتیبانی",
content: "آیا پشتیبانی فنی برای این روش ارائه می‌شود؟",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد کتاب",
content: "پیشنهاد می‌کنم کتاب مرجع معرفی کنید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد گواهینامه",
content: "آیا گواهینامه‌ای برای این روش ارائه می‌شود؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از جزئیات",
content: "جزئیات ارائه شده بسیار کامل و دقیق بود.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد جامعه کاربران",
content: "آیا جامعه کاربران فعالی برای این روش وجود دارد؟",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد انجمن",
content: "پیشنهاد می‌کنم انجمن کاربران تشکیل دهید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد آینده",
content: "آینده این روش چگونه خواهد بود؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از نوآوری",
content: "ممنون از نوآوری و خلاقیت در ارائه مطالب.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد رقبا",
content: "آیا روش‌های رقیب دیگری وجود دارد؟",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد تحقیق",
content: "پیشنهاد می‌کنم تحقیقات بیشتری در این زمینه انجام دهید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد استانداردها",
content: "آیا استاندارد خاصی برای این روش وجود دارد؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از شفافیت",
content: "ممنون از شفافیت در ارائه اطلاعات.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد امنیت",
content: "آیا این روش از نظر امنیتی مطمئن است؟",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد تست",
content: "پیشنهاد می‌کنم امکان تست رایگان فراهم کنید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد کیفیت",
content: "چگونه می‌توان کیفیت نتایج را ارزیابی کرد؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از پشتیبانی",
content: "ممنون از پشتیبانی کامل شما در این زمینه.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد توسعه",
content: "آیا امکان توسعه و سفارشی‌سازی وجود دارد؟",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد همکاری",
content: "آیا امکان همکاری در توسعه این روش وجود دارد؟",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد آموزش",
content: "آیا دوره‌های آموزشی برای این روش ارائه می‌شود؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از تلاش",
content: "ممنون از تلاش و زحمات شما در این زمینه.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد مجوزها",
content: "آیا مجوز خاصی برای استفاده از این روش نیاز است؟",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد بهینه‌سازی",
content: "پیشنهاد می‌کنم روش‌های بهینه‌سازی را هم بررسی کنید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد سازگاری",
content: "آیا این روش با سیستم‌های قدیمی سازگار است؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از صبر",
content: "ممنون از صبر و حوصله شما در پاسخ‌گویی.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد عملکرد",
content: "عملکرد این روش در شرایط مختلف چگونه است؟",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد مقایسه",
content: "پیشنهاد می‌کنم جدول مقایسه با روش‌های دیگر ارائه دهید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد نگهداری",
content: "آیا نگهداری این روش پیچیده است؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از دقت",
content: "ممنون از دقت و توجه شما به جزئیات.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد مقیاس‌پذیری",
content: "آیا این روش قابلیت مقیاس‌پذیری دارد؟",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد چک‌لیست",
content: "پیشنهاد می‌کنم چک‌لیست پیاده‌سازی ارائه دهید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد خطاها",
content: "رایج‌ترین خطاها در پیاده‌سازی چیست؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از راهنمایی",
content: "ممنون از راهنمایی‌های مفید شما.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد بک‌آپ",
content: "آیا نیاز به بک‌آپ خاصی وجود دارد؟",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد FAQ",
content: "پیشنهاد می‌کنم بخش سوالات متداول اضافه کنید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد بروزرسانی",
content: "چگونه می‌توان سیستم را بروزرسانی کرد؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از وقت",
content: "ممنون از وقتی که برای پاسخ‌گویی گذاشتید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد مانیتورینگ",
content: "آیا ابزار مانیتورینگ خاصی پیشنهاد می‌کنید؟",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد گلاسری",
content: "پیشنهاد می‌کنم گلاسری اصطلاحات اضافه کنید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد لاگ‌ها",
content: "چگونه می‌توان لاگ‌ها را بررسی کرد؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از کیفیت",
content: "ممنون از کیفیت بالای مطالب ارائه شده.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد تست",
content: "چه روش‌های تستی پیشنهاد می‌کنید؟",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد نمودار",
content: "پیشنهاد می‌کنم نمودار فرآیند اضافه کنید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد دیباگ",
content: "چگونه می‌توان مشکلات را دیباگ کرد؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از انگیزه",
content: "ممنون از انگیزه‌ای که به ما دادید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد کانفیگ",
content: "آیا کانفیگ خاصی نیاز است؟",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد تمپلیت",
content: "پیشنهاد می‌کنم تمپلیت آماده ارائه دهید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد پرفورمنس",
content: "چگونه می‌توان پرفورمنس را بهبود داد؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از صداقت",
content: "ممنون از صداقت در بیان محدودیت‌ها.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد مهاجرت",
content: "چگونه می‌توان از روش قدیمی مهاجرت کرد؟",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد ابزار",
content: "پیشنهاد می‌کنم ابزارهای کمکی معرفی کنید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد اتوماسیون",
content: "آیا امکان اتوماسیون فرآیند وجود دارد؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از تجربه",
content: "ممنون از به اشتراک گذاری تجربیات شخصی.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد API",
content: "آیا API خاصی برای این روش وجود دارد؟",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد مثال کاربردی",
content: "پیشنهاد می‌کنم مثال‌های کاربردی بیشتری اضافه کنید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد داکیومنت",
content: "آیا داکیومنت کاملی برای این روش وجود دارد؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از حرفه‌ای بودن",
content: "ممنون از رویکرد حرفه‌ای شما.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد لایسنس",
content: "آیا محدودیت لایسنسی وجود دارد؟",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد کیس استادی",
content: "پیشنهاد می‌کنم کیس استادی ارائه دهید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد ترابلشوتینگ",
content: "راهنمای ترابلشوتینگ کجا موجود است؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از پیگیری",
content: "ممنون از پیگیری مداوم شما.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد کمیونیتی",
content: "آیا کمیونیتی فعالی برای این روش وجود دارد؟",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد وبینار",
content: "پیشنهاد می‌کنم وبینار آموزشی برگزار کنید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد بست پرکتیس",
content: "بهترین شیوه‌های پیاده‌سازی چیست؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از انعطاف‌پذیری",
content: "ممنون از انعطاف‌پذیری در پاسخ‌گویی.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد ورکفلو",
content: "آیا ورکفلو خاصی برای این روش پیشنهاد می‌کنید؟",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد چارت",
content: "پیشنهاد می‌کنم چارت مقایسه ارائه دهید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد ریپورتینگ",
content: "چگونه می‌توان گزارش‌گیری کرد؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از صبوری",
content: "ممنون از صبوری شما در توضیح مطالب.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد انتگریشن",
content: "آیا امکان انتگریشن با سیستم‌های دیگر وجود دارد؟",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد پادکست",
content: "پیشنهاد می‌کنم پادکست آموزشی تولید کنید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد کاستومایزیشن",
content: "تا چه حد امکان سفارشی‌سازی وجود دارد؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از دسترسی",
content: "ممنون از در دسترس قرار دادن این اطلاعات.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد رولبک",
content: "آیا امکان بازگشت به حالت قبل وجود دارد؟",
status: CommentStatus.APPROVED,
},
{
title: "پیشنهاد بلاگ",
content: "پیشنهاد می‌کنم بلاگ تخصصی راه‌اندازی کنید.",
status: CommentStatus.APPROVED,
},
{
title: "سوال در مورد ورژن‌بندی",
content: "چگونه ورژن‌بندی انجام می‌شود؟",
status: CommentStatus.APPROVED,
},
{
title: "تشکر از مسئولیت‌پذیری",
content: "ممنون از مسئولیت‌پذیری شما در این زمینه.",
status: CommentStatus.APPROVED,
},
];
export const seedBlogComments = async (dataSource: DataSource, logger: Logger) => {
try {
const commentRepo = dataSource.getRepository(BlogComment);
const blogRepo = dataSource.getRepository(Blog);
const userRepo = dataSource.getRepository(User);
// Get existing blogs and users
const blogs = await blogRepo.find({ where: { deletedAt: IsNull() }, take: 10, order: { createdAt: "DESC" } });
const users = await userRepo.find({ take: 10 });
if (blogs.length === 0) {
logger.warn("No blogs found. Please seed blogs first.");
return;
}
if (users.length === 0) {
logger.warn("No users found. Please seed users first.");
return;
}
for (const commentData of blogComments) {
// Randomly select blog and user
const randomBlog = blogs[Math.floor(Math.random() * blogs.length)];
const randomUser = users[Math.floor(Math.random() * users.length)];
const comment = commentRepo.create({
...commentData,
blog: randomBlog,
user: randomUser,
});
await commentRepo.save(comment);
logger.log(`Blog comment "${commentData.title}" created successfully`);
}
logger.log("Blog comments seeding completed");
} catch (error) {
logger.error("Error in seeding blog comments", error);
process.exit(1);
}
};
+2 -1
View File
@@ -32,6 +32,7 @@
"dependencies": {
"@aws-sdk/client-s3": "^3.879.0",
"@aws-sdk/s3-request-presigner": "^3.879.0",
"@fastify/compress": "^8.1.0",
"@fastify/static": "^8.2.0",
"@keyv/redis": "^4.6.0",
"@nest-lab/fastify-multer": "^1.3.0",
@@ -60,7 +61,7 @@
"dayjs": "^1.11.18",
"decimal.js": "^10.6.0",
"dotenv": "^16.6.1",
"fastify": "^5.5.0",
"fastify": "^5.4.0",
"handlebars": "^4.7.8",
"nestjs-soap": "^3.0.4",
"nestjs-telegraf": "^2.9.1",
+133 -23
View File
@@ -14,6 +14,9 @@ importers:
'@aws-sdk/s3-request-presigner':
specifier: ^3.879.0
version: 3.879.0
'@fastify/compress':
specifier: ^8.1.0
version: 8.1.0
'@fastify/static':
specifier: ^8.2.0
version: 8.2.0
@@ -99,8 +102,8 @@ importers:
specifier: ^16.6.1
version: 16.6.1
fastify:
specifier: ^5.5.0
version: 5.5.0
specifier: ^5.4.0
version: 5.4.0
handlebars:
specifier: ^4.7.8
version: 4.7.8
@@ -789,6 +792,9 @@ packages:
resolution: {integrity: sha512-7PQA7EH43S0CxcOa9OeAnaeA0oQ+e/DHNPZwSQM9CQHW76jle5+OvLdibRp/Aafs9KXbLhxyjOTkRjWUbQEd3Q==}
engines: {node: '>=14'}
'@fastify/compress@8.1.0':
resolution: {integrity: sha512-wX3I5u/SYQXxbqjG7CysvzeaCe4Sv8y13MnvnaGTpqfKkJbTLpwvdIDgqrwp/+UGvXOW7OLDLoTAQCDMJJRjDQ==}
'@fastify/cors@11.1.0':
resolution: {integrity: sha512-sUw8ed8wP2SouWZTIbA7V2OQtMNpLj2W6qJOYhNdcmINTu6gsxVYXjQiM9mdi8UUDlcoDDJ/W2syPo1WB2QjYA==}
@@ -2815,6 +2821,12 @@ packages:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
duplexify@3.7.1:
resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==}
duplexify@4.1.3:
resolution: {integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==}
eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
@@ -2854,6 +2866,9 @@ packages:
resolution: {integrity: sha512-EuJWwlHPZ1LbADuKTClvHtwbaFn4rOD+dRAbWysqEOXRc2Uui0hJInNJrsdH0c+OhJA4nrCBdSkW4DD5YxAo6A==}
engines: {node: '>=8.10.0'}
end-of-stream@1.4.5:
resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==}
enhanced-resolve@5.18.3:
resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==}
engines: {node: '>=10.13.0'}
@@ -3155,9 +3170,6 @@ packages:
fastify@5.4.0:
resolution: {integrity: sha512-I4dVlUe+WNQAhKSyv15w+dwUh2EPiEl4X2lGYMmNSgF83WzTMAPKGdWEv5tPsCQOb+SOZwz8Vlta2vF+OeDgRw==}
fastify@5.5.0:
resolution: {integrity: sha512-ZWSWlzj3K/DcULCnCjEiC2zn2FBPdlZsSA/pnPa/dbUfLvxkD/Nqmb0XXMXLrWkeM4uQPUvjdJpwtXmTfriXqw==}
fastq@1.19.1:
resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}
@@ -4707,6 +4719,9 @@ packages:
peberminta@0.9.0:
resolution: {integrity: sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==}
peek-stream@1.1.3:
resolution: {integrity: sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA==}
pg-cloudflare@1.2.7:
resolution: {integrity: sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==}
@@ -4824,12 +4839,19 @@ packages:
resolution: {integrity: sha512-ZtV1YrwscEjlrUzYrTSs6Nwo49JM3pXLM4fFOBSC3wSni+bxaWlw9/Qgk75PZO8M7cX2EybmL2iwvaV3vkAttw==}
engines: {node: '>=14'}
process-nextick-args@2.0.1:
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
process-warning@4.0.1:
resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==}
process-warning@5.0.0:
resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==}
process@0.11.10:
resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==}
engines: {node: '>= 0.6.0'}
prom-client@15.1.3:
resolution: {integrity: sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g==}
engines: {node: ^16 || ^18 || >=20}
@@ -4883,6 +4905,12 @@ packages:
pug@3.0.3:
resolution: {integrity: sha512-uBi6kmc9f3SZ3PXxqcHiUZLmIXgfgWooKWXcwSGwQd2Zi5Rb0bT14+8CJjJgI8AB+nndLaNgHGrcc6bPIB665g==}
pump@3.0.3:
resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==}
pumpify@2.0.1:
resolution: {integrity: sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==}
punycode.js@2.3.1:
resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==}
engines: {node: '>=6'}
@@ -4922,10 +4950,17 @@ packages:
react-is@18.3.1:
resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==}
readable-stream@2.3.8:
resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
readable-stream@3.6.2:
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
engines: {node: '>= 6'}
readable-stream@4.7.0:
resolution: {integrity: sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
@@ -5041,6 +5076,9 @@ packages:
resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}
engines: {node: '>=0.4'}
safe-buffer@5.1.2:
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
safe-buffer@5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
@@ -5246,6 +5284,9 @@ packages:
resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
engines: {node: '>= 0.4'}
stream-shift@1.0.3:
resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==}
string-argv@0.3.2:
resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==}
engines: {node: '>=0.6.19'}
@@ -5278,6 +5319,9 @@ packages:
resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
engines: {node: '>= 0.4'}
string_decoder@1.1.1:
resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
string_decoder@1.3.0:
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
@@ -5406,6 +5450,9 @@ packages:
thread-stream@3.1.0:
resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==}
through2@2.0.5:
resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==}
through@2.3.8:
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
@@ -6881,6 +6928,17 @@ snapshots:
dependencies:
text-decoding: 1.0.0
'@fastify/compress@8.1.0':
dependencies:
'@fastify/accept-negotiator': 2.0.1
fastify-plugin: 5.0.1
mime-db: 1.52.0
minipass: 7.1.2
peek-stream: 1.1.3
pump: 3.0.3
pumpify: 2.0.1
readable-stream: 4.7.0
'@fastify/cors@11.1.0':
dependencies:
fastify-plugin: 5.0.1
@@ -9327,6 +9385,20 @@ snapshots:
es-errors: 1.3.0
gopd: 1.2.0
duplexify@3.7.1:
dependencies:
end-of-stream: 1.4.5
inherits: 2.0.4
readable-stream: 2.3.8
stream-shift: 1.0.3
duplexify@4.1.3:
dependencies:
end-of-stream: 1.4.5
inherits: 2.0.4
readable-stream: 3.6.2
stream-shift: 1.0.3
eastasianwidth@0.2.0: {}
ecdsa-sig-formatter@1.0.11:
@@ -9361,6 +9433,10 @@ snapshots:
encoding-japanese@2.2.0:
optional: true
end-of-stream@1.4.5:
dependencies:
once: 1.4.0
enhanced-resolve@5.18.3:
dependencies:
graceful-fs: 4.2.11
@@ -9774,24 +9850,6 @@ snapshots:
semver: 7.7.2
toad-cache: 3.7.0
fastify@5.5.0:
dependencies:
'@fastify/ajv-compiler': 4.0.2
'@fastify/error': 4.2.0
'@fastify/fast-json-stringify-compiler': 5.0.3
'@fastify/proxy-addr': 5.0.0
abstract-logging: 2.0.1
avvio: 9.1.0
fast-json-stringify: 6.0.1
find-my-way: 9.3.0
light-my-request: 6.6.0
pino: 9.9.0
process-warning: 5.0.0
rfdc: 1.4.1
secure-json-parse: 4.0.0
semver: 7.7.2
toad-cache: 3.7.0
fastq@1.19.1:
dependencies:
reusify: 1.1.0
@@ -11838,6 +11896,12 @@ snapshots:
peberminta@0.9.0:
optional: true
peek-stream@1.1.3:
dependencies:
buffer-from: 1.1.2
duplexify: 3.7.1
through2: 2.0.5
pg-cloudflare@1.2.7:
optional: true
@@ -11952,10 +12016,14 @@ snapshots:
uuid: 9.0.1
optional: true
process-nextick-args@2.0.1: {}
process-warning@4.0.1: {}
process-warning@5.0.0: {}
process@0.11.10: {}
prom-client@15.1.3:
dependencies:
'@opentelemetry/api': 1.9.0
@@ -12055,6 +12123,17 @@ snapshots:
pug-strip-comments: 2.0.0
optional: true
pump@3.0.3:
dependencies:
end-of-stream: 1.4.5
once: 1.4.0
pumpify@2.0.1:
dependencies:
duplexify: 4.1.3
inherits: 2.0.4
pump: 3.0.3
punycode.js@2.3.1:
optional: true
@@ -12088,12 +12167,30 @@ snapshots:
react-is@18.3.1: {}
readable-stream@2.3.8:
dependencies:
core-util-is: 1.0.3
inherits: 2.0.4
isarray: 1.0.0
process-nextick-args: 2.0.1
safe-buffer: 5.1.2
string_decoder: 1.1.1
util-deprecate: 1.0.2
readable-stream@3.6.2:
dependencies:
inherits: 2.0.4
string_decoder: 1.3.0
util-deprecate: 1.0.2
readable-stream@4.7.0:
dependencies:
abort-controller: 3.0.0
buffer: 6.0.3
events: 3.3.0
process: 0.11.10
string_decoder: 1.3.0
readdirp@3.6.0:
dependencies:
picomatch: 2.3.1
@@ -12213,6 +12310,8 @@ snapshots:
has-symbols: 1.1.0
isarray: 2.0.5
safe-buffer@5.1.2: {}
safe-buffer@5.2.1: {}
safe-compare@1.1.4:
@@ -12430,6 +12529,8 @@ snapshots:
es-errors: 1.3.0
internal-slot: 1.1.0
stream-shift@1.0.3: {}
string-argv@0.3.2: {}
string-length@4.0.2:
@@ -12478,6 +12579,10 @@ snapshots:
define-properties: 1.2.1
es-object-atoms: 1.1.1
string_decoder@1.1.1:
dependencies:
safe-buffer: 5.1.2
string_decoder@1.3.0:
dependencies:
safe-buffer: 5.2.1
@@ -12612,6 +12717,11 @@ snapshots:
dependencies:
real-require: 0.2.0
through2@2.0.5:
dependencies:
readable-stream: 2.3.8
xtend: 4.0.2
through@2.3.8: {}
tinyexec@1.0.1: {}
+3
View File
@@ -1,3 +1,4 @@
import compression from "@fastify/compress";
import { ClassSerializerInterceptor, Logger, ValidationPipe } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { NestFactory, Reflector } from "@nestjs/core";
@@ -22,6 +23,8 @@ async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(AppModule, fastifyAdapter);
await app.register(compression, { encodings: ["gzip", "deflate"] });
app.useGlobalPipes(new ValidationPipe({ transform: true, whitelist: true }));
app.useGlobalInterceptors(new ResponseInterceptor(), new PaginationInterceptor(), new ClassSerializerInterceptor(app.get(Reflector)));
app.useGlobalFilters(new HttpExceptionFilter());
@@ -109,21 +109,21 @@ export class CreateServiceDto {
@IsNotEmpty({ message: ServiceMessage.IMAGES_REQUIRED })
@IsString({ each: true })
@IsUrl({ protocols: ["http", "https"], require_protocol: true }, { message: ServiceMessage.IMAGES_SHOULD_BE_URL })
@IsUrl({ protocols: ["http", "https"], require_protocol: true }, { message: ServiceMessage.IMAGES_SHOULD_BE_URL, each: true })
@ApiProperty({ description: "The images of the service", example: ["https://example.com/image1.png", "https://example.com/image2.png"] })
images: string[];
@IsOptional()
@IsNotEmpty({ message: ServiceMessage.AUDIOS_REQUIRED })
@IsString({ each: true })
@IsUrl({ protocols: ["http", "https"], require_protocol: true }, { message: ServiceMessage.AUDIOS_SHOULD_BE_URL })
@IsUrl({ protocols: ["http", "https"], require_protocol: true }, { message: ServiceMessage.AUDIOS_SHOULD_BE_URL, each: true })
@ApiProperty({ description: "The audios of the service", example: ["https://example.com/audio1.mp3", "https://example.com/audio2.mp3"] })
audios?: string[];
@IsOptional()
@IsNotEmpty({ message: ServiceMessage.VIDEOS_REQUIRED })
@IsString({ each: true })
@IsUrl({ protocols: ["http", "https"], require_protocol: true }, { message: ServiceMessage.VIDEOS_SHOULD_BE_URL })
@IsUrl({ protocols: ["http", "https"], require_protocol: true }, { message: ServiceMessage.VIDEOS_SHOULD_BE_URL, each: true })
@ApiProperty({ description: "The videos of the service", example: ["https://example.com/video1.mp4", "https://example.com/video2.mp4"] })
videos?: string[];
@@ -1,5 +1,5 @@
import { BadRequestException, Injectable, Logger } from "@nestjs/common";
import { DataSource, FindOptionsWhere, In, IsNull, Not, QueryRunner } from "typeorm";
import { DataSource, FindOptionsWhere, In, IsNull, LessThan, MoreThan, Not, QueryRunner } from "typeorm";
import { ParamDto } from "../../../common/DTO/param.dto";
import { CategoryMessage, CommonMessage, ServiceMessage } from "../../../common/enums/message.enum";
@@ -718,19 +718,61 @@ export class DanakServicesService {
/******************************************** */
private async checkUserPurchasedService(userId: string, serviceId: string, queryRunner?: QueryRunner) {
const subscription = await (queryRunner ? queryRunner.manager : this.danakServicesRepository)
.createQueryBuilder()
.select("1")
.from("user_subscription", "us")
.innerJoin("subscription_plan", "sp", "us.planId = sp.id")
.where("us.userId = :userId", { userId })
.andWhere("sp.serviceId = :serviceId", { serviceId })
.andWhere(`(us.status = '${SubscriptionStatus.ACTIVE}')`)
.andWhere("us.endDate > NOW()")
.andWhere("us.startDate < NOW()")
.limit(1)
.getRawOne();
// const subscription = await (queryRunner ? queryRunner.manager : this.danakServicesRepository)
// .createQueryBuilder()
// .select("1")
// .from("user_subscription", "us")
// .innerJoin("subscription_plan", "sp", "us.planId = sp.id")
// .where("us.userId = :userId", { userId })
// .andWhere("sp.serviceId = :serviceId", { serviceId })
// .andWhere(`(us.status = '${SubscriptionStatus.ACTIVE}')`)
// .andWhere("us.endDate > NOW()")
// .andWhere("us.startDate < NOW()")
// .limit(1)
// .getRawOne();
return !!subscription;
if (!queryRunner) {
const subscription = await this.danakServicesRepository.findOne({
where: {
id: serviceId,
subscriptionPlans: {
userSubscriptions: {
user: { id: userId },
status: SubscriptionStatus.ACTIVE,
endDate: MoreThan(new Date()),
startDate: LessThan(new Date()),
},
},
},
relations: {
subscriptionPlans: {
userSubscriptions: {
user: true,
},
},
},
});
return !!subscription;
} else {
const subscription = await queryRunner.manager.findOne(this.danakServicesRepository.target, {
where: {
id: serviceId,
subscriptionPlans: {
userSubscriptions: {
user: { id: userId },
status: SubscriptionStatus.ACTIVE,
endDate: MoreThan(new Date()),
startDate: LessThan(new Date()),
},
},
},
relations: {
subscriptionPlans: {
userSubscriptions: { user: true },
},
},
});
return !!subscription;
}
}
}