crtisim
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -21,6 +21,7 @@ import { RequestModule } from './modules/request/request.module';
|
|||||||
import { InvoiceModule } from './modules/invoice/invoice.module';
|
import { InvoiceModule } from './modules/invoice/invoice.module';
|
||||||
import { OrderModule } from './modules/order/order.module';
|
import { OrderModule } from './modules/order/order.module';
|
||||||
import { LearningModule } from './modules/learnings/learning.module';
|
import { LearningModule } from './modules/learnings/learning.module';
|
||||||
|
import { CriticismModule } from './modules/criticisms/criticisms.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -50,6 +51,7 @@ import { LearningModule } from './modules/learnings/learning.module';
|
|||||||
InvoiceModule,
|
InvoiceModule,
|
||||||
OrderModule,
|
OrderModule,
|
||||||
LearningModule,
|
LearningModule,
|
||||||
|
CriticismModule,
|
||||||
],
|
],
|
||||||
controllers: [],
|
controllers: [],
|
||||||
providers: [],
|
providers: [],
|
||||||
|
|||||||
@@ -137,6 +137,17 @@ export const enum LearningMessage {
|
|||||||
VIDEO_DURATION_INVALID = 'مدت زمان ویدیو نامعتبر است',
|
VIDEO_DURATION_INVALID = 'مدت زمان ویدیو نامعتبر است',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const enum CriticismMessage {
|
||||||
|
NOT_FOUND = 'انتقاد مورد نظر یافت نشد',
|
||||||
|
TITLE_IS_REQUIRED = 'عنوان الزامی است',
|
||||||
|
TITLE_STRING = 'عنوان باید رشته باشد',
|
||||||
|
CONTENT_IS_REQUIRED = 'محتوا الزامی است',
|
||||||
|
CONTENT_IS_STRING = 'محتوا باید رشته باشد',
|
||||||
|
FILES_IS_REQUIRED = 'فایلها الزامی است',
|
||||||
|
FILES_SHOULD_BE_URL = 'آدرس فایل باید URL معتبر باشد',
|
||||||
|
SEARCH_QUERY_STRING = 'رشته جستجو باید یک رشته باشد',
|
||||||
|
}
|
||||||
|
|
||||||
export const enum productMessage {
|
export const enum productMessage {
|
||||||
NOT_FOUND = 'کالایی با این مشخصات یافت نشد',
|
NOT_FOUND = 'کالایی با این مشخصات یافت نشد',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ export enum PermissionEnum {
|
|||||||
MANAGE_PRINT = 'view_print',
|
MANAGE_PRINT = 'view_print',
|
||||||
|
|
||||||
MANAGE_LEARNINGS = 'manage_learnings',
|
MANAGE_LEARNINGS = 'manage_learnings',
|
||||||
|
|
||||||
|
MANAGE_CRITICISMS = 'manage_criticisms',
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -77,5 +79,6 @@ export const PermissionTitles: Record<PermissionEnum, string> = {
|
|||||||
[PermissionEnum.DELETE_ORDER]: "",
|
[PermissionEnum.DELETE_ORDER]: "",
|
||||||
[PermissionEnum.CREATE_PRINT]: "ایجاد فرم چاپ برای سفارش",
|
[PermissionEnum.CREATE_PRINT]: "ایجاد فرم چاپ برای سفارش",
|
||||||
[PermissionEnum.MANAGE_PRINT]: "مدیریت فرم چاپ",
|
[PermissionEnum.MANAGE_PRINT]: "مدیریت فرم چاپ",
|
||||||
[PermissionEnum.MANAGE_LEARNINGS]: "مدیریت آموزشها"
|
[PermissionEnum.MANAGE_LEARNINGS]: "مدیریت آموزشها",
|
||||||
|
[PermissionEnum.MANAGE_CRITICISMS]: "مدیریت انتقادها و پیشنهادها"
|
||||||
};
|
};
|
||||||
|
|||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
import { ApiProperty } from "@nestjs/swagger";
|
||||||
|
import { IsNotEmpty, IsOptional, IsString, IsUrl } from "class-validator";
|
||||||
|
|
||||||
|
import { CriticismMessage } from "../../../common/enums/message.enum";
|
||||||
|
|
||||||
|
export class CreateCriticismDto {
|
||||||
|
@IsNotEmpty({ message: CriticismMessage.TITLE_IS_REQUIRED })
|
||||||
|
@IsString({ message: CriticismMessage.TITLE_STRING })
|
||||||
|
@ApiProperty({ type: String, description: "title of criticism", example: "انتقاد بابت مشکلات" })
|
||||||
|
title: string;
|
||||||
|
|
||||||
|
@IsNotEmpty({ message: CriticismMessage.CONTENT_IS_REQUIRED })
|
||||||
|
@IsString({ message: CriticismMessage.CONTENT_IS_STRING })
|
||||||
|
@ApiProperty({ type: String, description: "description of criticism", example: "متن انتقاد" })
|
||||||
|
content: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsUrl({ protocols: ['http', 'https'], require_protocol: true }, { message: CriticismMessage.FILES_SHOULD_BE_URL, each: true })
|
||||||
|
@ApiProperty({
|
||||||
|
description: "The ulr of the criticism files",
|
||||||
|
example: ["https://example.com/image1.png", "https://example.com/image2.png"],
|
||||||
|
})
|
||||||
|
files: string[];
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
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 SearchCriticismQueryDto extends PaginationDto {
|
||||||
|
@IsOptional()
|
||||||
|
@IsDateString()
|
||||||
|
@ApiPropertyOptional({ description: "since query", example: "2025-01-27" })
|
||||||
|
since?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString({ message: CriticismMessage.SEARCH_QUERY_STRING })
|
||||||
|
@ApiPropertyOptional({ description: "Search query", example: "search query" })
|
||||||
|
q?: string;
|
||||||
|
}
|
||||||
+49
@@ -0,0 +1,49 @@
|
|||||||
|
import { Body, Controller, Delete, Get, Param, Post, Query, UseGuards } from '@nestjs/common';
|
||||||
|
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
import { CreateCriticismDto } from './DTO/create-criticism.dto';
|
||||||
|
import { SearchCriticismQueryDto } from './DTO/search-criticism-query.dto';
|
||||||
|
import { CriticismsService } from './providers/criticisms.service';
|
||||||
|
import { AuthGuard } from '../auth/guards/auth.guard';
|
||||||
|
import { AdminAuthGuard } from '../auth/guards/adminAuth.guard';
|
||||||
|
import { Permissions } from '../../common/decorators/permissions.decorator';
|
||||||
|
import { UserId } from '../../common/decorators';
|
||||||
|
import { PermissionEnum } from '../../common/enums/permission.enum';
|
||||||
|
|
||||||
|
@ApiTags('Criticism')
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@Controller('criticisms')
|
||||||
|
export class CriticismController {
|
||||||
|
constructor(private readonly criticismService: CriticismsService) {}
|
||||||
|
|
||||||
|
@Post()
|
||||||
|
@UseGuards(AuthGuard)
|
||||||
|
@ApiOperation({ summary: 'Create a new criticism' })
|
||||||
|
create(@Body() createDto: CreateCriticismDto, @UserId() userId: string) {
|
||||||
|
return this.criticismService.create(createDto, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get()
|
||||||
|
@UseGuards(AdminAuthGuard)
|
||||||
|
@Permissions(PermissionEnum.MANAGE_CRITICISMS)
|
||||||
|
@ApiOperation({ summary: 'Get all criticisms (admin only)' })
|
||||||
|
findAll(@Query() queryDto: SearchCriticismQueryDto) {
|
||||||
|
return this.criticismService.findAll(queryDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get(':id')
|
||||||
|
@UseGuards(AdminAuthGuard)
|
||||||
|
@Permissions(PermissionEnum.MANAGE_CRITICISMS)
|
||||||
|
@ApiOperation({ summary: 'Get one criticism by id (admin only)' })
|
||||||
|
findOne(@Param('id') id: string) {
|
||||||
|
return this.criticismService.findOneAndMarkAsRead(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete(':id')
|
||||||
|
@UseGuards(AdminAuthGuard)
|
||||||
|
@Permissions(PermissionEnum.MANAGE_CRITICISMS)
|
||||||
|
@ApiOperation({ summary: 'Delete one criticism by id (admin only)' })
|
||||||
|
delete(@Param('id') id: string) {
|
||||||
|
return this.criticismService.delete(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+27
@@ -0,0 +1,27 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { MikroOrmModule } from '@mikro-orm/nestjs';
|
||||||
|
|
||||||
|
import { CriticismController } from './criticisms.controller';
|
||||||
|
import { CriticismFile } from './entities/criticism-file.entity';
|
||||||
|
import { Criticism } from './entities/criticism.entity';
|
||||||
|
import { CriticismsService } from './providers/criticisms.service';
|
||||||
|
import { CriticismFileRepository } from './repositories/criticisms-file.repository';
|
||||||
|
import { CriticismRepository } from './repositories/criticisms.repository';
|
||||||
|
import { UserModule } from '../user/user.module';
|
||||||
|
import { NotificationsModule } from '../notification/notifications.module';
|
||||||
|
import { AdminModule } from '../admin/admin.module';
|
||||||
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [
|
||||||
|
MikroOrmModule.forFeature([Criticism, CriticismFile]),
|
||||||
|
UserModule,
|
||||||
|
NotificationsModule,
|
||||||
|
AdminModule,
|
||||||
|
JwtModule
|
||||||
|
],
|
||||||
|
providers: [CriticismsService, CriticismRepository, CriticismFileRepository],
|
||||||
|
controllers: [CriticismController],
|
||||||
|
exports: [CriticismsService],
|
||||||
|
})
|
||||||
|
export class CriticismModule {}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { Entity, ManyToOne, OptionalProps, Property } from '@mikro-orm/core';
|
||||||
|
import { BaseEntity } from '../../../common/entities/base.entity';
|
||||||
|
import { Criticism } from './criticism.entity';
|
||||||
|
|
||||||
|
@Entity({ tableName: 'criticism_files' })
|
||||||
|
export class CriticismFile extends BaseEntity {
|
||||||
|
[OptionalProps]?: 'createdAt' | 'deletedAt';
|
||||||
|
|
||||||
|
@Property({ type: 'varchar', length: 255 })
|
||||||
|
fileUrl: string;
|
||||||
|
|
||||||
|
@ManyToOne(() => Criticism)
|
||||||
|
criticism: Criticism;
|
||||||
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
import { Cascade, Collection, Entity, ManyToOne, OneToMany, OptionalProps, Property } from '@mikro-orm/core';
|
||||||
|
import { BaseEntity } from '../../../common/entities/base.entity';
|
||||||
|
import { User } from '../../user/entities/user.entity';
|
||||||
|
import { CriticismFile } from './criticism-file.entity';
|
||||||
|
|
||||||
|
@Entity({ tableName: 'criticisms' })
|
||||||
|
export class Criticism extends BaseEntity {
|
||||||
|
[OptionalProps]?: 'createdAt' | 'deletedAt';
|
||||||
|
|
||||||
|
@Property({ type: 'varchar', length: 150 })
|
||||||
|
title: string;
|
||||||
|
|
||||||
|
@Property({ type: 'text' })
|
||||||
|
content: string;
|
||||||
|
|
||||||
|
@ManyToOne(() => User)
|
||||||
|
user: User;
|
||||||
|
|
||||||
|
@Property({ default: false })
|
||||||
|
isRead: boolean = false;
|
||||||
|
|
||||||
|
@OneToMany(() => CriticismFile, (criticismFile) => criticismFile.criticism, { cascade: [Cascade.ALL] })
|
||||||
|
files = new Collection<CriticismFile>(this);
|
||||||
|
}
|
||||||
+135
@@ -0,0 +1,135 @@
|
|||||||
|
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||||
|
import { EntityManager } from '@mikro-orm/postgresql';
|
||||||
|
import { CommonMessage, CriticismMessage } from '../../../common/enums/message.enum';
|
||||||
|
import { NotificationQueueService } from '../../notification/services/notification-queue.service';
|
||||||
|
import { AdminRepository } from '../../admin/repositories/admin.repository';
|
||||||
|
import { PermissionEnum } from '../../../common/enums/permission.enum';
|
||||||
|
import { NotifEvent } from '../../notification/interfaces/notification.interface';
|
||||||
|
import { Notification } from '../../notification/entities/notification.entity';
|
||||||
|
import { CreateCriticismDto } from '../DTO/create-criticism.dto';
|
||||||
|
import { SearchCriticismQueryDto } from '../DTO/search-criticism-query.dto';
|
||||||
|
import { Criticism } from '../entities/criticism.entity';
|
||||||
|
import { CriticismFile } from '../entities/criticism-file.entity';
|
||||||
|
import { CriticismRepository } from '../repositories/criticisms.repository';
|
||||||
|
import { UserService } from '../../user/providers/user.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class CriticismsService {
|
||||||
|
constructor(
|
||||||
|
private readonly criticismRepository: CriticismRepository,
|
||||||
|
private readonly userService: UserService,
|
||||||
|
private readonly em: EntityManager,
|
||||||
|
private readonly adminRepository: AdminRepository,
|
||||||
|
private readonly notificationQueueService: NotificationQueueService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async create(createDto: CreateCriticismDto, userId: string) {
|
||||||
|
return this.em.transactional(async (em) => {
|
||||||
|
const user = await this.userService.findOrFail(userId);
|
||||||
|
|
||||||
|
const criticism = em.create(Criticism, {
|
||||||
|
title: createDto.title,
|
||||||
|
content: createDto.content,
|
||||||
|
user,
|
||||||
|
isRead: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const fileUrl of createDto.files ?? []) {
|
||||||
|
const file = em.create(CriticismFile, { fileUrl, criticism });
|
||||||
|
criticism.files.add(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
await em.persistAndFlush(criticism);
|
||||||
|
|
||||||
|
await this.notifyAdminsWithPermission(criticism, em);
|
||||||
|
|
||||||
|
return {
|
||||||
|
message: CommonMessage.CREATED,
|
||||||
|
criticism,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async findAll(queryDto: SearchCriticismQueryDto) {
|
||||||
|
const page = queryDto.page ?? 1;
|
||||||
|
const limit = queryDto.limit ?? 10;
|
||||||
|
const offset = (page - 1) * limit;
|
||||||
|
|
||||||
|
const where: Record<string, unknown> = {};
|
||||||
|
|
||||||
|
if (queryDto.since) {
|
||||||
|
where.createdAt = { $gte: new Date(queryDto.since) };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queryDto.q) {
|
||||||
|
where.title = { $like: `%${queryDto.q}%` };
|
||||||
|
}
|
||||||
|
|
||||||
|
const [criticisms, count] = await this.em.findAndCount(Criticism, where, {
|
||||||
|
orderBy: { createdAt: 'DESC' },
|
||||||
|
offset,
|
||||||
|
limit,
|
||||||
|
populate: ['user', 'files'],
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
criticisms,
|
||||||
|
count,
|
||||||
|
paginate: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async findOneAndMarkAsRead(id: string) {
|
||||||
|
const criticism = await this.criticismRepository.findOne(
|
||||||
|
{ id },
|
||||||
|
{ populate: ['user', 'files'] },
|
||||||
|
);
|
||||||
|
if (!criticism) throw new BadRequestException(CriticismMessage.NOT_FOUND);
|
||||||
|
criticism.isRead = true;
|
||||||
|
await this.em.flush();
|
||||||
|
return {
|
||||||
|
criticism,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(id: string) {
|
||||||
|
const criticism = await this.criticismRepository.findOne({ id });
|
||||||
|
if (!criticism) throw new BadRequestException(CriticismMessage.NOT_FOUND);
|
||||||
|
|
||||||
|
await this.em.removeAndFlush(criticism);
|
||||||
|
return {
|
||||||
|
message: CommonMessage.DELETED,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async notifyAdminsWithPermission(criticism: Criticism, em: EntityManager) {
|
||||||
|
const admins = await this.adminRepository.findAdminsWithPermission(
|
||||||
|
PermissionEnum.MANAGE_CRITICISMS,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (admins.length === 0) return;
|
||||||
|
|
||||||
|
const user = criticism.user;
|
||||||
|
const fullName = `${user.firstName ?? ''} ${user.lastName ?? ''}`.trim() || 'کاربر';
|
||||||
|
const body = `انتقاد جدید از ${fullName}: ${criticism.title}`;
|
||||||
|
|
||||||
|
const notifications = admins.map((admin) =>
|
||||||
|
em.create(Notification, {
|
||||||
|
admin,
|
||||||
|
title: NotifEvent.NEW_CRITICISM,
|
||||||
|
content: body,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
await em.persistAndFlush(notifications);
|
||||||
|
|
||||||
|
await this.notificationQueueService.addBulkInAppNotifications(
|
||||||
|
notifications.map((n) => ({
|
||||||
|
recipient: { adminId: n.admin!.id },
|
||||||
|
subject: NotifEvent.NEW_CRITICISM,
|
||||||
|
body,
|
||||||
|
notificationId: n.id,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { EntityManager, EntityRepository } from '@mikro-orm/postgresql';
|
||||||
|
import { CriticismFile } from '../entities/criticism-file.entity';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class CriticismFileRepository extends EntityRepository<CriticismFile> {
|
||||||
|
constructor(readonly em: EntityManager) {
|
||||||
|
super(em, CriticismFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { EntityManager, EntityRepository } from '@mikro-orm/postgresql';
|
||||||
|
import { Criticism } from '../entities/criticism.entity';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class CriticismRepository extends EntityRepository<Criticism> {
|
||||||
|
constructor(readonly em: EntityManager) {
|
||||||
|
super(em, Criticism);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ export enum NotifEvent {
|
|||||||
NEW_ORDER = 'newOrder', // for chapkhane sms bere
|
NEW_ORDER = 'newOrder', // for chapkhane sms bere
|
||||||
DESIGNER_ASSIGN = 'designerAssign',
|
DESIGNER_ASSIGN = 'designerAssign',
|
||||||
PAYMENT_SUCCESS = 'paymentSuccess',
|
PAYMENT_SUCCESS = 'paymentSuccess',
|
||||||
|
NEW_CRITICISM = 'newCriticism',
|
||||||
}
|
}
|
||||||
export type recipientType = { userId: string } | { adminId: string };
|
export type recipientType = { userId: string } | { adminId: string };
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { UserModule } from '../user/user.module';
|
|||||||
import { UtilsModule } from '../util/utils.module';
|
import { UtilsModule } from '../util/utils.module';
|
||||||
import { ProductModule } from '../product/product.module';
|
import { ProductModule } from '../product/product.module';
|
||||||
import { TicketModule } from '../ticket/ticket.module';
|
import { TicketModule } from '../ticket/ticket.module';
|
||||||
|
import { OrderPrintRepository } from './repositories/order-print.repository';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -32,7 +33,7 @@ import { TicketModule } from '../ticket/ticket.module';
|
|||||||
],
|
],
|
||||||
controllers: [OrderController],
|
controllers: [OrderController],
|
||||||
providers: [OrderService, OrderRepository, OrderListeners,
|
providers: [OrderService, OrderRepository, OrderListeners,
|
||||||
OrdersCrone,],
|
OrdersCrone, OrderPrintRepository],
|
||||||
exports: [OrderRepository, OrderService],
|
exports: [OrderRepository, OrderService],
|
||||||
})
|
})
|
||||||
export class OrderModule { }
|
export class OrderModule { }
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Entity, Index, Property, OneToMany, Collection, Cascade, PrimaryKey, OptionalProps } from '@mikro-orm/core';
|
import { Entity, Index, Property, OneToMany, Collection, PrimaryKey, OptionalProps } from '@mikro-orm/core';
|
||||||
import { BaseEntity } from '../../../common/entities/base.entity';
|
import { BaseEntity } from '../../../common/entities/base.entity';
|
||||||
import { LearningProgress } from '../../learnings/entities/learning-progress.entity';
|
import { LearningProgress } from '../../learnings/entities/learning-progress.entity';
|
||||||
|
import { Criticism } from '../../criticisms/entities/criticism.entity';
|
||||||
// import { Order } from 'src/modules/order/entities/order.entity';
|
// import { Order } from 'src/modules/order/entities/order.entity';
|
||||||
import { normalizePhone } from '../../util/phone.util';
|
import { normalizePhone } from '../../util/phone.util';
|
||||||
import { ulid } from 'ulid';
|
import { ulid } from 'ulid';
|
||||||
@@ -12,6 +13,9 @@ export class User extends BaseEntity {
|
|||||||
@OneToMany(() => LearningProgress, (lp) => lp.user)
|
@OneToMany(() => LearningProgress, (lp) => lp.user)
|
||||||
learningProgress = new Collection<LearningProgress>(this);
|
learningProgress = new Collection<LearningProgress>(this);
|
||||||
|
|
||||||
|
@OneToMany(() => Criticism, (c) => c.user)
|
||||||
|
criticisms = new Collection<Criticism>(this);
|
||||||
|
|
||||||
// @OneToMany(() => Order, order => order.user)
|
// @OneToMany(() => Order, order => order.user)
|
||||||
// orders = new Collection<Order>(this);
|
// orders = new Collection<Order>(this);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user