chore: add landing module

This commit is contained in:
mahyargdz
2025-04-13 11:57:03 +03:30
parent 78f481871c
commit 6f55f7a1d6
14 changed files with 210 additions and 81 deletions
+8 -5
View File
@@ -7,13 +7,13 @@ import { ConfigModule } from "@nestjs/config";
import { ThrottlerModule } from "@nestjs/throttler"; import { ThrottlerModule } from "@nestjs/throttler";
import { TypeOrmModule } from "@nestjs/typeorm"; import { TypeOrmModule } from "@nestjs/typeorm";
import { MailerModule } from "@nestjs-modules/mailer"; import { MailerModule } from "@nestjs-modules/mailer";
import { TelegrafModule } from "nestjs-telegraf"; // import { TelegrafModule } from "nestjs-telegraf";
import { bullMqConfig } from "./configs/bullmq.config"; import { bullMqConfig } from "./configs/bullmq.config";
import { cacheConfig } from "./configs/cache.config"; import { cacheConfig } from "./configs/cache.config";
import { mailerConfig } from "./configs/mailer.config"; import { mailerConfig } from "./configs/mailer.config";
import { rateLimitConfig } from "./configs/rateLimit.config"; import { rateLimitConfig } from "./configs/rateLimit.config";
import { telegrafConfig } from "./configs/telegraf.config"; // import { telegrafConfig } from "./configs/telegraf.config";
import { databaseConfigs } from "./configs/typeorm.config"; import { databaseConfigs } from "./configs/typeorm.config";
import { HTTPLogger } from "./core/middlewares/logger.middleware"; import { HTTPLogger } from "./core/middlewares/logger.middleware";
import { AddressModule } from "./modules/address/address.module"; import { AddressModule } from "./modules/address/address.module";
@@ -26,8 +26,9 @@ import { CriticismModule } from "./modules/criticisms/criticisms.module";
import { DanakServicesModule } from "./modules/danak-services/danak-services.module"; import { DanakServicesModule } from "./modules/danak-services/danak-services.module";
import { DashboardModule } from "./modules/dashboards/dashboard.module"; import { DashboardModule } from "./modules/dashboards/dashboard.module";
import { InvoicesModule } from "./modules/invoices/invoices.module"; import { InvoicesModule } from "./modules/invoices/invoices.module";
import { LandingModule } from "./modules/landing/landing.module";
import { LearningModule } from "./modules/learnings/learning.module"; import { LearningModule } from "./modules/learnings/learning.module";
import { LoggerModule } from "./modules/logger/logger.module"; // import { LoggerModule } from "./modules/logger/logger.module";
import { NotificationModule } from "./modules/notifications/notifications.module"; import { NotificationModule } from "./modules/notifications/notifications.module";
import { PaymentsModule } from "./modules/payments/payments.module"; import { PaymentsModule } from "./modules/payments/payments.module";
import { SettingModule } from "./modules/settings/settings.module"; import { SettingModule } from "./modules/settings/settings.module";
@@ -36,9 +37,10 @@ import { TicketsModule } from "./modules/tickets/tickets.module";
import { UploaderModule } from "./modules/uploader/uploader.module"; import { UploaderModule } from "./modules/uploader/uploader.module";
import { UsersModule } from "./modules/users/users.module"; import { UsersModule } from "./modules/users/users.module";
import { WalletsModule } from "./modules/wallets/wallets.module"; import { WalletsModule } from "./modules/wallets/wallets.module";
@Module({ @Module({
imports: [ imports: [
TelegrafModule.forRootAsync(telegrafConfig()), // TelegrafModule.forRootAsync(telegrafConfig()),
MailerModule.forRootAsync(mailerConfig()), MailerModule.forRootAsync(mailerConfig()),
BullModule.forRootAsync(bullMqConfig()), BullModule.forRootAsync(bullMqConfig()),
ThrottlerModule.forRootAsync(rateLimitConfig()), ThrottlerModule.forRootAsync(rateLimitConfig()),
@@ -66,7 +68,8 @@ import { WalletsModule } from "./modules/wallets/wallets.module";
AddressModule, AddressModule,
DashboardModule, DashboardModule,
BlogsModule, BlogsModule,
LoggerModule, // LoggerModule,
LandingModule,
], ],
controllers: [], controllers: [],
}) })
+1
View File
@@ -25,6 +25,7 @@ export class CreateBlogDto {
@IsNotEmpty({ message: BlogMessage.IMAGE_URL_REQUIRED }) @IsNotEmpty({ message: BlogMessage.IMAGE_URL_REQUIRED })
@IsString({ message: BlogMessage.IMAGE_URL_STRING }) @IsString({ message: BlogMessage.IMAGE_URL_STRING })
@MaxLength(150, { message: BlogMessage.IMAGE_URL_MAX_LENGTH }) @MaxLength(150, { message: BlogMessage.IMAGE_URL_MAX_LENGTH })
@ApiProperty({ description: "Image URL of the blog", example: "https://example.com/image.jpg" })
imageUrl: string; imageUrl: string;
@IsNotEmpty({ message: BlogMessage.META_TITLE_REQUIRED }) @IsNotEmpty({ message: BlogMessage.META_TITLE_REQUIRED })
@@ -1,4 +1,4 @@
import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Patch, Post, Put, Query } from "@nestjs/common"; import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Patch, Post, Query } from "@nestjs/common";
import { ApiOperation } from "@nestjs/swagger"; import { ApiOperation } from "@nestjs/swagger";
import { AdminRoute } from "../../../common/decorators/admin.decorator"; import { AdminRoute } from "../../../common/decorators/admin.decorator";
@@ -32,6 +32,13 @@ export class BlogsController {
return this.blogsService.getBlogsPublic(queryDto); return this.blogsService.getBlogsPublic(queryDto);
} }
@ApiOperation({ summary: "Get most visited and pinned blogs" })
@SkipAuth()
@Get("combined")
getCombinedBlogs() {
return this.blogsService.getCombinedBlogs();
}
@ApiOperation({ summary: "Get all blogs (admin route)" }) @ApiOperation({ summary: "Get all blogs (admin route)" })
@AdminRoute() @AdminRoute()
@PermissionsDec(PermissionEnum.BLOGS) @PermissionsDec(PermissionEnum.BLOGS)
@@ -127,7 +134,7 @@ export class BlogsController {
@ApiOperation({ summary: "Update the status of a comment (admin route)" }) @ApiOperation({ summary: "Update the status of a comment (admin route)" })
@AdminRoute() @AdminRoute()
@PermissionsDec(PermissionEnum.BLOGS) @PermissionsDec(PermissionEnum.BLOGS)
@Put("comments/:id/status") @Patch("comments/:id/status")
updateCommentStatus(@Param() paramDto: ParamDto, @Body() updateCommentStatusDto: UpdateCommentStatusDto) { updateCommentStatus(@Param() paramDto: ParamDto, @Body() updateCommentStatusDto: UpdateCommentStatusDto) {
return this.blogsService.updateCommentStatus(paramDto.id, updateCommentStatusDto); return this.blogsService.updateCommentStatus(paramDto.id, updateCommentStatusDto);
} }
@@ -162,7 +169,7 @@ export class BlogsController {
} }
@ApiOperation({ summary: "Update a category (admin route)" }) @ApiOperation({ summary: "Update a category (admin route)" })
@Put("categories/:id") @Patch("categories/:id")
@AdminRoute() @AdminRoute()
@PermissionsDec(PermissionEnum.BLOGS) @PermissionsDec(PermissionEnum.BLOGS)
updateCategory(@Param() paramDto: ParamDto, @Body() updateCategoryDto: UpdateCategoryDto) { updateCategory(@Param() paramDto: ParamDto, @Body() updateCategoryDto: UpdateCategoryDto) {
+20 -2
View File
@@ -175,8 +175,23 @@ export class BlogsService {
//*********************************** */ //*********************************** */
async getBlogsPublic(queryDto: BlogSearchQueryDto) { async getBlogsPublic(queryDto: BlogSearchQueryDto) {
const blogs = await this.blogsRepository.getBlogsForUserSide(queryDto); const [blogs, count] = await this.blogsRepository.getBlogsForUserSide(queryDto);
return { blogs };
//;
return {
blogs,
count,
paginate: true,
};
}
//*********************************** */
async getCombinedBlogs() {
const [pinnedBlogs, mostVisitedBlogs] = await Promise.all([
this.blogsRepository.getPinnedBlogs(),
this.blogsRepository.getMostVisitedBlogs(),
]);
return { pinnedBlogs, mostVisitedBlogs };
} }
//*********************************** */ //*********************************** */
@@ -244,17 +259,20 @@ export class BlogsService {
return category; return category;
} }
//*********************************** */
async incrementViewCount(id: string) { async incrementViewCount(id: string) {
const blog = await this.findBlogById(id); const blog = await this.findBlogById(id);
blog.viewCount += 1; blog.viewCount += 1;
await this.blogsRepository.save(blog); await this.blogsRepository.save(blog);
return { message: "View count incremented successfully" }; return { message: "View count incremented successfully" };
} }
//*********************************** */
async getMostVisitedBlogs() { async getMostVisitedBlogs() {
const blogs = await this.blogsRepository.getMostVisitedBlogs(); const blogs = await this.blogsRepository.getMostVisitedBlogs();
return { blogs }; return { blogs };
} }
//*********************************** */
async getPinnedBlogs() { async getPinnedBlogs() {
const blogs = await this.blogsRepository.getPinnedBlogs(); const blogs = await this.blogsRepository.getPinnedBlogs();
@@ -49,7 +49,7 @@ export class DanakServicesController {
return this.danakServicesService.getCategoryList(queryDto); return this.danakServicesService.getCategoryList(queryDto);
} }
@AuthGuards() // @AuthGuards()
@ApiOperation({ summary: "Get all service categories user side" }) @ApiOperation({ summary: "Get all service categories user side" })
@Get("categories/public") @Get("categories/public")
getCategoriesUserSide() { getCategoriesUserSide() {
@@ -106,7 +106,7 @@ export class DanakServicesController {
} }
@ApiOperation({ summary: "get all danak services for user side" }) @ApiOperation({ summary: "get all danak services for user side" })
@AuthGuards() // @AuthGuards()
@Get("public") @Get("public")
getServicesForUser(@Query() queryDto: DanakServicesQueryDto) { getServicesForUser(@Query() queryDto: DanakServicesQueryDto) {
return this.danakServicesService.getServicesListForUser(queryDto); return this.danakServicesService.getServicesListForUser(queryDto);
+15
View File
@@ -0,0 +1,15 @@
import { Controller, Get } from "@nestjs/common";
import { ApiOperation } from "@nestjs/swagger";
import { LandingService } from "./providers/landing.service";
@Controller("landing")
export class LandingController {
constructor(private readonly landingService: LandingService) {}
@ApiOperation({ summary: "Get all landing page data" })
@Get()
async getLandingData() {
return this.landingService.getLandingData();
}
}
+15
View File
@@ -0,0 +1,15 @@
import { Module } from "@nestjs/common";
import { LandingController } from "./landing.controller";
import { LandingService } from "./providers/landing.service";
import { BlogsModule } from "../blogs/blogs.module";
import { DanakServicesModule } from "../danak-services/danak-services.module";
import { SlidersModule } from "../sliders/sliders.module";
@Module({
imports: [SlidersModule, BlogsModule, DanakServicesModule],
controllers: [LandingController],
providers: [LandingService],
exports: [LandingService],
})
export class LandingModule {}
@@ -0,0 +1,27 @@
import { Injectable } from "@nestjs/common";
import { BlogsService } from "../../blogs/providers/blogs.service";
import { DanakServicesService } from "../../danak-services/providers/danak-services.service";
import { SlidersService } from "../../sliders/providers/sliders.service";
@Injectable()
export class LandingService {
constructor(
private readonly slidersService: SlidersService,
private readonly blogsService: BlogsService,
private readonly danakServices: DanakServicesService,
) {}
async getLandingData() {
const [sliders, pinnedBlogs, danakSuggestServices] = await Promise.all([
this.slidersService.getSlidersListForLanding(),
this.blogsService.getPinnedBlogs(),
this.danakServices.getDanakSuggestServices(),
]);
return {
sliders,
pinnedBlogs: pinnedBlogs.blogs,
danakSuggestServices: danakSuggestServices.danakServices,
};
}
}
@@ -14,7 +14,7 @@ export class Slider extends BaseEntity {
imageUrl: string; imageUrl: string;
@Column({ length: 255, nullable: true }) @Column({ length: 255, nullable: true })
link: string; link?: string;
@Column({ default: 0 }) @Column({ default: 0 })
order: number; order: number;
@@ -1,48 +0,0 @@
import { Injectable, NotFoundException } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { SliderMessage } from "../../../common/enums/message.enum";
import { CreateSliderDto } from "../DTO/create-slider.dto";
import { UpdateSliderDto } from "../DTO/update-slider.dto";
import { Slider } from "../entities/slider.entity";
@Injectable()
export class SliderService {
constructor(
@InjectRepository(Slider)
private readonly sliderRepository: Repository<Slider>,
) {}
async create(createSliderDto: CreateSliderDto): Promise<Slider> {
const slider = this.sliderRepository.create(createSliderDto);
return await this.sliderRepository.save(slider);
}
async findAll(): Promise<Slider[]> {
return await this.sliderRepository.find({
order: {
order: "ASC",
},
});
}
async getSliderById(id: string): Promise<Slider> {
const slider = await this.sliderRepository.findOne({ where: { id } });
if (!slider) {
throw new NotFoundException(SliderMessage.SLIDER_NOT_FOUND);
}
return slider;
}
async update(id: string, updateSliderDto: UpdateSliderDto): Promise<Slider> {
const slider = await this.getSliderById(id);
Object.assign(slider, updateSliderDto);
return await this.sliderRepository.save(slider);
}
async remove(id: string): Promise<void> {
const slider = await this.getSliderById(id);
await this.sliderRepository.remove(slider);
}
}
@@ -0,0 +1,73 @@
import { Injectable, NotFoundException } from "@nestjs/common";
import { PaginationDto } from "../../../common/DTO/pagination.dto";
import { CommonMessage, SliderMessage } from "../../../common/enums/message.enum";
import { CreateSliderDto } from "../DTO/create-slider.dto";
import { UpdateSliderDto } from "../DTO/update-slider.dto";
import { SlidersRepository } from "../repositories/sliders.repository";
@Injectable()
export class SlidersService {
constructor(private readonly slidersRepository: SlidersRepository) {}
async create(createSliderDto: CreateSliderDto) {
const slider = this.slidersRepository.create(createSliderDto);
await this.slidersRepository.save(slider);
return {
message: CommonMessage.CREATED,
slider,
};
}
//*************************** */
async getSlidersList(queryDto: PaginationDto) {
const [sliders, count] = await this.slidersRepository.getSlidersListForAdmin(queryDto);
return {
sliders,
count,
paginate: true,
};
}
//************************* */
async getSliderById(id: string) {
const slider = await this.slidersRepository.findOne({ where: { id } });
if (!slider) throw new NotFoundException(SliderMessage.SLIDER_NOT_FOUND);
return {
slider,
};
}
//****************** */
async update(id: string, updateSliderDto: UpdateSliderDto) {
const { slider } = await this.getSliderById(id);
await this.slidersRepository.save({ ...slider, ...updateSliderDto });
return {
message: CommonMessage.UPDATE_SUCCESS,
};
}
//****************** */
async remove(id: string) {
const { slider } = await this.getSliderById(id);
await this.slidersRepository.remove(slider);
return {
message: CommonMessage.DELETED,
};
}
//****************** */
async toggleSliderStatus(id: string) {
const { slider } = await this.getSliderById(id);
slider.isActive = !slider.isActive;
await this.slidersRepository.save(slider);
return {
message: CommonMessage.UPDATE_SUCCESS,
};
}
//****************** */
async getSlidersListForLanding() {
const sliders = await this.slidersRepository.find({ where: { isActive: true } });
return sliders;
}
//****************** */
}
@@ -2,6 +2,8 @@ import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm"; import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm"; import { Repository } from "typeorm";
import { PaginationDto } from "../../../common/DTO/pagination.dto";
import { PaginationUtils } from "../../utils/providers/pagination.utils";
import { Slider } from "../entities/slider.entity"; import { Slider } from "../entities/slider.entity";
@Injectable() @Injectable()
@@ -9,4 +11,16 @@ export class SlidersRepository extends Repository<Slider> {
constructor(@InjectRepository(Slider) repository: Repository<Slider>) { constructor(@InjectRepository(Slider) repository: Repository<Slider>) {
super(repository.target, repository.manager, repository.queryRunner); super(repository.target, repository.manager, repository.queryRunner);
} }
async getSlidersListForAdmin(queryDto: PaginationDto) {
const { skip, limit } = PaginationUtils(queryDto);
return this.findAndCount({
skip,
take: limit,
order: {
order: "ASC",
},
});
}
} }
@@ -1,49 +1,53 @@
import { Body, Controller, Delete, Get, Param, Patch, Post } from "@nestjs/common"; import { Body, Controller, Delete, Get, Param, Patch, Post, Query } from "@nestjs/common";
import { ApiOperation } from "@nestjs/swagger"; import { ApiOperation } from "@nestjs/swagger";
import { CreateSliderDto } from "./DTO/create-slider.dto"; import { CreateSliderDto } from "./DTO/create-slider.dto";
import { UpdateSliderDto } from "./DTO/update-slider.dto"; import { UpdateSliderDto } from "./DTO/update-slider.dto";
import { SliderService } from "./providers/slider.service"; import { SlidersService } from "./providers/sliders.service";
import { AdminRoute } from "../../common/decorators/admin.decorator";
import { AuthGuards } from "../../common/decorators/auth-guard.decorator"; import { AuthGuards } from "../../common/decorators/auth-guard.decorator";
import { SkipAuth } from "../../common/decorators/skip-auth.decorator"; import { PaginationDto } from "../../common/DTO/pagination.dto";
import { ParamDto } from "../../common/DTO/param.dto"; import { ParamDto } from "../../common/DTO/param.dto";
// import { PermissionsDec } from "../../common/decorators/permission.decorator"; // import { PermissionsDec } from "../../common/decorators/permission.decorator";
@Controller("sliders") @Controller("sliders")
@AuthGuards() @AuthGuards()
export class SliderController { export class SlidersController {
constructor(private readonly sliderService: SliderService) {} constructor(private readonly slidersService: SlidersService) {}
@ApiOperation({ summary: "create slider (admin route)" }) @ApiOperation({ summary: "create slider (admin route)" })
@AdminRoute()
// @PermissionsDec(PermissionEnum.SLIDER) // @PermissionsDec(PermissionEnum.SLIDER)
@Post() @Post()
create(@Body() createSliderDto: CreateSliderDto) { create(@Body() createSliderDto: CreateSliderDto) {
return this.sliderService.create(createSliderDto); return this.slidersService.create(createSliderDto);
} }
@ApiOperation({ summary: "Get all sliders" }) @ApiOperation({ summary: "Get all sliders" })
@SkipAuth() @AdminRoute()
@Get() @Get()
findAll() { getSlidersList(@Query() queryDto: PaginationDto) {
return this.sliderService.findAll(); return this.slidersService.getSlidersList(queryDto);
} }
@Get(":id")
@ApiOperation({ summary: "Get a slider by id" }) @ApiOperation({ summary: "Get a slider by id" })
@SkipAuth() @AdminRoute()
@Get(":id")
getSliderById(@Param() paramDto: ParamDto) { getSliderById(@Param() paramDto: ParamDto) {
return this.sliderService.getSliderById(paramDto.id); return this.slidersService.getSliderById(paramDto.id);
} }
@ApiOperation({ summary: "Update a slider" }) @ApiOperation({ summary: "Update a slider" })
@AdminRoute()
@Patch(":id") @Patch(":id")
update(@Param() paramDto: ParamDto, @Body() updateSliderDto: UpdateSliderDto) { update(@Param() paramDto: ParamDto, @Body() updateSliderDto: UpdateSliderDto) {
return this.sliderService.update(paramDto.id, updateSliderDto); return this.slidersService.update(paramDto.id, updateSliderDto);
} }
@ApiOperation({ summary: "Delete a slider" }) @ApiOperation({ summary: "Delete a slider" })
@AdminRoute()
@Delete(":id") @Delete(":id")
remove(@Param() paramDto: ParamDto) { remove(@Param() paramDto: ParamDto) {
return this.sliderService.remove(paramDto.id); return this.slidersService.remove(paramDto.id);
} }
} }
@@ -2,14 +2,14 @@ import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm"; import { TypeOrmModule } from "@nestjs/typeorm";
import { Slider } from "./entities/slider.entity"; import { Slider } from "./entities/slider.entity";
import { SliderService } from "./providers/slider.service"; import { SlidersService } from "./providers/sliders.service";
import { SlidersRepository } from "./repositories/sliders.repository"; import { SlidersRepository } from "./repositories/sliders.repository";
import { SliderController } from "./slider.controller"; import { SlidersController } from "./sliders.controller";
@Module({ @Module({
imports: [TypeOrmModule.forFeature([Slider])], imports: [TypeOrmModule.forFeature([Slider])],
controllers: [SliderController], controllers: [SlidersController],
providers: [SliderService, SlidersRepository], providers: [SlidersService, SlidersRepository],
exports: [SliderService], exports: [SlidersService],
}) })
export class SliderModule {} export class SlidersModule {}