chore: create,get all announcements with pagination
This commit is contained in:
@@ -128,6 +128,10 @@ export const enum AnnouncementMessage {
|
|||||||
CONTENT_IS_REQUIRED = "متن اطلاعیه مورد نیاز است",
|
CONTENT_IS_REQUIRED = "متن اطلاعیه مورد نیاز است",
|
||||||
CONTENT_IS_STRING = "متن اطلاعیه باید رشته باشد",
|
CONTENT_IS_STRING = "متن اطلاعیه باید رشته باشد",
|
||||||
CONTENT_MUST_BE_LONGER = "متن اطلاعیه باید حداقل ۱۰ کاراکتر باشد",
|
CONTENT_MUST_BE_LONGER = "متن اطلاعیه باید حداقل ۱۰ کاراکتر باشد",
|
||||||
|
PUBLISH_AT_IS_REQUIRED = "تاریخ انتشار اطلاعیه مورد نیاز است",
|
||||||
|
SERVICE_MUST_BE_UUID = "شناسه سرویس باید یک UUID معتبر باشد",
|
||||||
|
GROUP_MUST_BE_UUID = "شناسه گروه کاربران باید یک UUID معتبر باشد",
|
||||||
|
SERVICE_MUST_BE_ID = "ایدی سرویس اجباری است",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum CriticismMessage {
|
export const enum CriticismMessage {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ export class CreateAnnouncementDto {
|
|||||||
@IsNotEmpty({ message: AnnouncementMessage.TITLE_IS_REQUIRED })
|
@IsNotEmpty({ message: AnnouncementMessage.TITLE_IS_REQUIRED })
|
||||||
@IsString({ message: AnnouncementMessage.TITLE_STRING })
|
@IsString({ message: AnnouncementMessage.TITLE_STRING })
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
type: String,
|
|
||||||
description: "Title of the announcement",
|
description: "Title of the announcement",
|
||||||
example: "اطلاعیه جدید",
|
example: "اطلاعیه جدید",
|
||||||
})
|
})
|
||||||
@@ -17,25 +16,47 @@ export class CreateAnnouncementDto {
|
|||||||
@IsString({ message: AnnouncementMessage.CONTENT_IS_STRING })
|
@IsString({ message: AnnouncementMessage.CONTENT_IS_STRING })
|
||||||
@MinLength(10, { message: AnnouncementMessage.CONTENT_MUST_BE_LONGER })
|
@MinLength(10, { message: AnnouncementMessage.CONTENT_MUST_BE_LONGER })
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
type: String,
|
|
||||||
description: "Content of the announcement",
|
description: "Content of the announcement",
|
||||||
example: "اطلاعیه جدید برای کاربران",
|
example: "اطلاعیه جدید برای کاربران",
|
||||||
})
|
})
|
||||||
content: string;
|
content: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsNotEmpty({ message: AnnouncementMessage.PUBLISH_AT_IS_REQUIRED })
|
||||||
|
@ApiProperty({
|
||||||
|
description: "Publish date of the announcement",
|
||||||
|
example: "2023-10-01T10:00:00Z",
|
||||||
|
})
|
||||||
|
publishAt: Date;
|
||||||
|
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
type: Boolean,
|
description: "Is this announcement public?",
|
||||||
description: "Is this announcement important?",
|
|
||||||
example: false,
|
example: false,
|
||||||
})
|
})
|
||||||
isPublic: boolean;
|
isPublic: boolean;
|
||||||
|
|
||||||
|
@IsBoolean()
|
||||||
|
@ApiProperty({
|
||||||
|
description: "Is this announcement important?",
|
||||||
|
example: false,
|
||||||
|
})
|
||||||
|
isImportant: boolean;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsNotEmpty({ message: AnnouncementMessage.SERVICE_MUST_BE_ID })
|
||||||
|
@IsUUID("4", { message: AnnouncementMessage.SERVICE_MUST_BE_UUID })
|
||||||
|
@ApiProperty({
|
||||||
|
description: "Service ID",
|
||||||
|
example: "d290f1ee-6c54-4b01-90e6-d701748f0851",
|
||||||
|
})
|
||||||
|
serviceId: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsArray()
|
@IsArray()
|
||||||
@IsUUID("4", {
|
@IsUUID("4", {
|
||||||
each: true,
|
each: true,
|
||||||
message: "شناسه هر گروه باید یک UUID معتبر نسخه ۴ باشد",
|
message: AnnouncementMessage.GROUP_MUST_BE_UUID,
|
||||||
})
|
})
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
type: [String],
|
type: [String],
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { ApiPropertyOptional } from "@nestjs/swagger";
|
||||||
|
import { IsDateString, IsOptional, IsString } from "class-validator";
|
||||||
|
|
||||||
|
import { PaginationDto } from "../../../common/DTO/pagination.dto";
|
||||||
|
import { CriticismMessage } from "../../../common/enums/message.enum";
|
||||||
|
|
||||||
|
export class SearchAnnouncementQueryDto extends PaginationDto {
|
||||||
|
@IsOptional()
|
||||||
|
@IsDateString()
|
||||||
|
@ApiPropertyOptional({ description: "since query", example: "2025-01-27" })
|
||||||
|
since?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsDateString()
|
||||||
|
@ApiPropertyOptional({ description: "publishAt query", example: "2025-01-27" })
|
||||||
|
publishAt?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString({ message: CriticismMessage.SEARCH_QUERY_STRING })
|
||||||
|
@ApiPropertyOptional({ description: "Search query", example: "search query" })
|
||||||
|
q?: string;
|
||||||
|
}
|
||||||
@@ -1,8 +1,44 @@
|
|||||||
import { Controller } from "@nestjs/common";
|
import { Body, Controller, Get, Post, Query } from "@nestjs/common";
|
||||||
import { ApiTags } from "@nestjs/swagger";
|
import { ApiProperty, ApiTags } from "@nestjs/swagger";
|
||||||
|
|
||||||
|
import { AnnouncementService } from "./announcement.service";
|
||||||
|
import { CreateAnnouncementDto } from "./DTO/create-announcement.dto";
|
||||||
|
import { AuthGuards } from "../../common/decorators/auth-guard.decorator";
|
||||||
|
import { Roles } from "../../common/decorators/roles.decorator";
|
||||||
|
import { SearchCriticismQueryDto } from "../criticisms/DTO/search-criticism-query.dto";
|
||||||
|
import { RoleEnum } from "../users/enums/role.enum";
|
||||||
|
|
||||||
@ApiTags("Announcements")
|
@ApiTags("Announcements")
|
||||||
@Controller("announcements")
|
@Controller("announcements")
|
||||||
export class AnnouncementController {
|
export class AnnouncementController {
|
||||||
constructor() {}
|
constructor(private readonly announcementService: AnnouncementService) {}
|
||||||
|
|
||||||
|
@AuthGuards()
|
||||||
|
@Roles(RoleEnum.ADMIN)
|
||||||
|
@ApiProperty({
|
||||||
|
description: "Create a new announcement ===> login as admin",
|
||||||
|
})
|
||||||
|
@Post()
|
||||||
|
async create(@Body() createAnnouncementDto: CreateAnnouncementDto) {
|
||||||
|
return await this.announcementService.createAnnouncement(createAnnouncementDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AuthGuards()
|
||||||
|
@Roles(RoleEnum.ADMIN)
|
||||||
|
@ApiProperty({
|
||||||
|
description: "Get all announcements ===> login as admin",
|
||||||
|
})
|
||||||
|
@Get()
|
||||||
|
async getAllAnnouncements(@Query() queryDto: SearchCriticismQueryDto) {
|
||||||
|
return await this.announcementService.getAllAnnouncements(queryDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AuthGuards()
|
||||||
|
@ApiProperty({
|
||||||
|
description: "Get all public announcements",
|
||||||
|
})
|
||||||
|
@Get("public")
|
||||||
|
async getPublicAnnouncements() {
|
||||||
|
return await this.announcementService.getPublicAnnouncements();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,11 @@ import { AnnouncementController } from "./announcement.controller";
|
|||||||
import { AnnouncementService } from "./announcement.service";
|
import { AnnouncementService } from "./announcement.service";
|
||||||
import { Announcement } from "./entities/announcement.entity";
|
import { Announcement } from "./entities/announcement.entity";
|
||||||
import { AnnouncementRepository } from "./repositories/announcement.repository";
|
import { AnnouncementRepository } from "./repositories/announcement.repository";
|
||||||
|
import { DanakServicesModule } from "../danak-services/danak-services.module";
|
||||||
|
import { UsersModule } from "../users/users.module";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [TypeOrmModule.forFeature([Announcement])],
|
imports: [TypeOrmModule.forFeature([Announcement]), DanakServicesModule, UsersModule],
|
||||||
providers: [AnnouncementService, AnnouncementRepository],
|
providers: [AnnouncementService, AnnouncementRepository],
|
||||||
controllers: [AnnouncementController],
|
controllers: [AnnouncementController],
|
||||||
exports: [TypeOrmModule],
|
exports: [TypeOrmModule],
|
||||||
|
|||||||
@@ -1,10 +1,73 @@
|
|||||||
import { Injectable } from "@nestjs/common";
|
import { Injectable } from "@nestjs/common";
|
||||||
|
|
||||||
// import { AnnouncementRepository } from "./repositories/announcement.repository";
|
import { CreateAnnouncementDto } from "./DTO/create-announcement.dto";
|
||||||
|
import { SearchAnnouncementQueryDto } from "./DTO/search-announcement-query.dto";
|
||||||
|
import { AnnouncementRepository } from "./repositories/announcement.repository";
|
||||||
|
import { CommonMessage } from "../../common/enums/message.enum";
|
||||||
|
import { DanakServicesService } from "../danak-services/providers/danak-services.service";
|
||||||
|
import { UsersService } from "../users/providers/users.service";
|
||||||
|
import { PaginationUtils } from "../utils/providers/pagination.utils";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AnnouncementService {
|
export class AnnouncementService {
|
||||||
// constructor(private readonly announcementRepository: AnnouncementRepository) {}
|
constructor(
|
||||||
|
private readonly announcementRepository: AnnouncementRepository,
|
||||||
|
private readonly danakServicesService: DanakServicesService,
|
||||||
|
private readonly usersService: UsersService,
|
||||||
|
) {}
|
||||||
|
|
||||||
async createAnnouncement() {}
|
async createAnnouncement(createAnnouncementDto: CreateAnnouncementDto) {
|
||||||
|
let service;
|
||||||
|
let groups;
|
||||||
|
if (createAnnouncementDto.serviceId) {
|
||||||
|
service = await this.danakServicesService.findServiceById(createAnnouncementDto.serviceId);
|
||||||
|
}
|
||||||
|
if (createAnnouncementDto.groupIds) {
|
||||||
|
groups = await this.usersService.getUserGroupsByIds(createAnnouncementDto.groupIds);
|
||||||
|
}
|
||||||
|
const announcement = this.announcementRepository.create({
|
||||||
|
...createAnnouncementDto,
|
||||||
|
service,
|
||||||
|
targetGroups: groups?.userGroups,
|
||||||
|
});
|
||||||
|
await this.announcementRepository.save(announcement);
|
||||||
|
return {
|
||||||
|
message: CommonMessage.CREATED,
|
||||||
|
announcement,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAllAnnouncements(queryDto: SearchAnnouncementQueryDto) {
|
||||||
|
const { limit, skip } = PaginationUtils(queryDto);
|
||||||
|
|
||||||
|
const queryBuilder = this.announcementRepository
|
||||||
|
.createQueryBuilder("announcement")
|
||||||
|
.leftJoin("announcement.service", "danak_service")
|
||||||
|
.addSelect(["danak_service.id", "danak_service.name"])
|
||||||
|
.leftJoin("announcement.targetGroups", "group")
|
||||||
|
.addSelect(["group.id", "group.name"]);
|
||||||
|
|
||||||
|
if (queryDto.since) {
|
||||||
|
queryBuilder.andWhere("announcement.createdAt >= :since", { since: queryDto.since });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queryDto.publishAt) {
|
||||||
|
queryBuilder.andWhere("announcement.publishAt >= :publishAt", { publishAt: queryDto.publishAt });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queryDto.q) {
|
||||||
|
queryBuilder.andWhere("announcement.title LIKE :q", { q: `%${queryDto.q}%` });
|
||||||
|
}
|
||||||
|
|
||||||
|
queryBuilder.orderBy("announcement.createdAt", "DESC");
|
||||||
|
|
||||||
|
const [announcements, count] = await queryBuilder.skip(skip).take(limit).getManyAndCount();
|
||||||
|
|
||||||
|
return { announcements, count };
|
||||||
|
}
|
||||||
|
|
||||||
|
async getPublicAnnouncements() {
|
||||||
|
const announcements = await this.announcementRepository.find({ where: { isPublic: true }, relations: ["service", "targetGroups"] });
|
||||||
|
return { announcements };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ export class Announcement extends BaseEntity {
|
|||||||
@Column({ type: "timestamp", default: null, nullable: true })
|
@Column({ type: "timestamp", default: null, nullable: true })
|
||||||
publishAt: Date;
|
publishAt: Date;
|
||||||
|
|
||||||
//TODO: Add service here
|
|
||||||
//TODO: Add customer here
|
//TODO: Add customer here
|
||||||
@ManyToOne(() => DanakService, (service) => service.announcements, { eager: true, onDelete: "CASCADE" })
|
@ManyToOne(() => DanakService, (service) => service.announcements, { eager: true, onDelete: "CASCADE" })
|
||||||
service: DanakService;
|
service: DanakService;
|
||||||
|
|||||||
@@ -127,5 +127,12 @@ export class DanakServicesService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/******************************************** */
|
/******************************************** */
|
||||||
|
|
||||||
|
async findServiceById(id: string) {
|
||||||
|
const service = await this.danakServicesRepository.findOneBy({ id });
|
||||||
|
if (!service) throw new BadRequestException(ServiceMessage.SERVICE_NOT_EXIST);
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************** */
|
/******************************************** */
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,4 +143,14 @@ export class UsersService {
|
|||||||
userGroup,
|
userGroup,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///****************************************************** */
|
||||||
|
|
||||||
|
async getUserGroupsByIds(ids: string[]) {
|
||||||
|
const userGroups = await this.userGroupRepository.find({ where: { id: In(ids) } });
|
||||||
|
if (!userGroups) throw new BadRequestException(UserMessage.USER_GROUP_NOT_FOUND);
|
||||||
|
return {
|
||||||
|
userGroups,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user