build: include production build artifacts in repo

This commit is contained in:
S. Esmaeili
2026-10-24 10:11:05 +03:30
parent dfd8a82809
commit 7399812d0e
213 changed files with 65702 additions and 2 deletions
+214
View File
@@ -0,0 +1,214 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
import { Body, Controller, Delete, Get, HttpCode, Module, Param, Patch, Post, Put, Query, } from "@nestjs/common";
import { categoryInputSchema, productInputSchema, productListQuerySchema, reorderSchema, } from "@imen/shared";
import { z } from "zod";
import { AdminAuth, CurrentUser, Roles } from "../common/auth.js";
import { IdPipe, ZodPipe } from "../common/zod.pipe.js";
import { MediaModule } from "../media/media.controller.js";
import { CategoriesService } from "./categories.service.js";
import { ProductsService } from "./products.service.js";
const publishSchema = z.object({ isPublished: z.boolean() });
let CategoriesController = class CategoriesController {
categories;
constructor(categories) {
this.categories = categories;
}
list() {
return this.categories.list();
}
get(id) {
return this.categories.get(id);
}
create(body, user) {
return this.categories.create(body, user.id);
}
async reorder(body, user) {
await this.categories.reorder(body.ids, user.id);
}
update(id, body, user) {
return this.categories.update(id, body, user.id);
}
async remove(id, user) {
await this.categories.remove(id, user.id);
}
};
__decorate([
Get(),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], CategoriesController.prototype, "list", null);
__decorate([
Get(":id"),
__param(0, Param("id", IdPipe)),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Number]),
__metadata("design:returntype", void 0)
], CategoriesController.prototype, "get", null);
__decorate([
Post(),
__param(0, Body(new ZodPipe(categoryInputSchema))),
__param(1, CurrentUser()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", void 0)
], CategoriesController.prototype, "create", null);
__decorate([
Post("reorder"),
HttpCode(204),
__param(0, Body(new ZodPipe(reorderSchema))),
__param(1, CurrentUser()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], CategoriesController.prototype, "reorder", null);
__decorate([
Put(":id"),
__param(0, Param("id", IdPipe)),
__param(1, Body(new ZodPipe(categoryInputSchema))),
__param(2, CurrentUser()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Number, Object, Object]),
__metadata("design:returntype", void 0)
], CategoriesController.prototype, "update", null);
__decorate([
Roles("ADMIN"),
Delete(":id"),
HttpCode(204),
__param(0, Param("id", IdPipe)),
__param(1, CurrentUser()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Number, Object]),
__metadata("design:returntype", Promise)
], CategoriesController.prototype, "remove", null);
CategoriesController = __decorate([
AdminAuth(),
Controller("admin/categories"),
__metadata("design:paramtypes", [CategoriesService])
], CategoriesController);
export { CategoriesController };
let ProductsController = class ProductsController {
products;
constructor(products) {
this.products = products;
}
list(q) {
return this.products.list(q);
}
get(id) {
return this.products.get(id);
}
create(body, user) {
return this.products.create(body, user.id);
}
async reorder(body, user) {
await this.products.reorder(body.ids, user.id);
}
duplicate(id, user) {
return this.products.duplicate(id, user.id);
}
publish(id, body, user) {
return this.products.setPublished(id, body.isPublished, user.id);
}
update(id, body, user) {
return this.products.update(id, body, user.id);
}
async remove(id, user) {
await this.products.remove(id, user.id);
}
};
__decorate([
Get(),
__param(0, Query(new ZodPipe(productListQuerySchema))),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", void 0)
], ProductsController.prototype, "list", null);
__decorate([
Get(":id"),
__param(0, Param("id", IdPipe)),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Number]),
__metadata("design:returntype", void 0)
], ProductsController.prototype, "get", null);
__decorate([
Post(),
__param(0, Body(new ZodPipe(productInputSchema))),
__param(1, CurrentUser()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", void 0)
], ProductsController.prototype, "create", null);
__decorate([
Post("reorder"),
HttpCode(204),
__param(0, Body(new ZodPipe(reorderSchema))),
__param(1, CurrentUser()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object, Object]),
__metadata("design:returntype", Promise)
], ProductsController.prototype, "reorder", null);
__decorate([
Post(":id/duplicate"),
__param(0, Param("id", IdPipe)),
__param(1, CurrentUser()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Number, Object]),
__metadata("design:returntype", void 0)
], ProductsController.prototype, "duplicate", null);
__decorate([
Patch(":id/publish"),
__param(0, Param("id", IdPipe)),
__param(1, Body(new ZodPipe(publishSchema))),
__param(2, CurrentUser()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Number, Object, Object]),
__metadata("design:returntype", void 0)
], ProductsController.prototype, "publish", null);
__decorate([
Put(":id"),
__param(0, Param("id", IdPipe)),
__param(1, Body(new ZodPipe(productInputSchema))),
__param(2, CurrentUser()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Number, Object, Object]),
__metadata("design:returntype", void 0)
], ProductsController.prototype, "update", null);
__decorate([
Roles("ADMIN"),
Delete(":id"),
HttpCode(204),
__param(0, Param("id", IdPipe)),
__param(1, CurrentUser()),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Number, Object]),
__metadata("design:returntype", Promise)
], ProductsController.prototype, "remove", null);
ProductsController = __decorate([
AdminAuth(),
Controller("admin/products"),
__metadata("design:paramtypes", [ProductsService])
], ProductsController);
export { ProductsController };
let CatalogModule = class CatalogModule {
};
CatalogModule = __decorate([
Module({
imports: [MediaModule],
controllers: [CategoriesController, ProductsController],
providers: [CategoriesService, ProductsService],
})
], CatalogModule);
export { CatalogModule };
//# sourceMappingURL=catalog.module.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"catalog.module.js","sourceRoot":"","sources":["../../src/catalog/catalog.module.ts"],"names":[],"mappings":"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"}
+133
View File
@@ -0,0 +1,133 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { ConflictException, Injectable } from "@nestjs/common";
import { AuditService, RevalidateService } from "../common/common.module.js";
import { MediaService } from "../media/media.service.js";
import { PrismaService } from "../prisma/prisma.service.js";
const withCover = { coverImage: true };
let CategoriesService = class CategoriesService {
prisma;
media;
audit;
revalidate;
constructor(prisma, media, audit, revalidate) {
this.prisma = prisma;
this.media = media;
this.audit = audit;
this.revalidate = revalidate;
}
async list() {
const rows = await this.prisma.category.findMany({
orderBy: [{ sortOrder: "asc" }, { id: "asc" }],
include: { ...withCover, _count: { select: { products: true, groups: true } } },
});
return rows.map(({ coverImage, _count, ...c }) => ({
...c,
coverImage: coverImage && this.media.toDto(coverImage),
productCount: _count.products,
groupCount: _count.groups,
}));
}
async get(id) {
const { coverImage, ...c } = await this.prisma.category.findUniqueOrThrow({
where: { id },
include: {
...withCover,
groups: {
orderBy: { sortOrder: "asc" },
include: { _count: { select: { products: true } } },
},
},
});
return {
...c,
coverImage: coverImage && this.media.toDto(coverImage),
groups: c.groups.map(({ _count, ...g }) => ({ ...g, productCount: _count.products })),
};
}
async create(input, userId) {
this.assertUniqueGroupSlugs(input);
const { groups, ...data } = input;
const last = await this.prisma.category.aggregate({ _max: { sortOrder: true } });
const category = await this.prisma.category.create({
data: {
...data,
sortOrder: (last._max.sortOrder ?? -1) + 1,
groups: {
create: groups.map((g, i) => ({ slug: g.slug, name: g.name, desc: g.desc, sortOrder: i })),
},
},
});
this.audit.log(userId, "create", "category", category.id, category.name);
this.revalidate.trigger();
return this.get(category.id);
}
async update(id, input, userId) {
this.assertUniqueGroupSlugs(input);
const { groups, ...data } = input;
await this.prisma.$transaction(async (tx) => {
const category = await tx.category.update({ where: { id }, data });
const keepIds = groups.flatMap((g) => (g.id ? [g.id] : []));
await tx.productGroup.deleteMany({ where: { categoryId: id, id: { notIn: keepIds } } });
for (const g of groups) {
if (g.id) {
await tx.productGroup.update({
where: { id: g.id, categoryId: id },
data: { slug: `__tmp-${g.id}` },
});
}
}
for (const [i, g] of groups.entries()) {
const fields = { slug: g.slug, name: g.name, desc: g.desc, sortOrder: i };
if (g.id) {
await tx.productGroup.update({ where: { id: g.id, categoryId: id }, data: fields });
}
else {
await tx.productGroup.create({ data: { ...fields, categoryId: id } });
}
}
this.audit.log(userId, "update", "category", id, category.name);
});
this.revalidate.trigger();
return this.get(id);
}
async remove(id, userId) {
const category = await this.prisma.category.findUniqueOrThrow({
where: { id },
include: { _count: { select: { products: true } } },
});
if (category._count.products > 0) {
throw new ConflictException(`این دسته ${category._count.products} محصول دارد؛ ابتدا محصولات را حذف یا جابه‌جا کنید`);
}
await this.prisma.category.delete({ where: { id } });
this.audit.log(userId, "delete", "category", id, category.name);
this.revalidate.trigger();
}
async reorder(ids, userId) {
await this.prisma.$transaction(ids.map((id, i) => this.prisma.category.update({ where: { id }, data: { sortOrder: i } })));
this.audit.log(userId, "reorder", "category", "", `${ids.length} دسته`);
this.revalidate.trigger();
}
assertUniqueGroupSlugs(input) {
const slugs = input.groups.map((g) => g.slug);
if (new Set(slugs).size !== slugs.length) {
throw new ConflictException("اسلاگ زیرگروه‌ها باید یکتا باشد");
}
}
};
CategoriesService = __decorate([
Injectable(),
__metadata("design:paramtypes", [PrismaService,
MediaService,
AuditService,
RevalidateService])
], CategoriesService);
export { CategoriesService };
//# sourceMappingURL=categories.service.js.map
File diff suppressed because one or more lines are too long
+182
View File
@@ -0,0 +1,182 @@
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { BadRequestException, Injectable } from "@nestjs/common";
import { AuditService, RevalidateService } from "../common/common.module.js";
import { MediaService } from "../media/media.service.js";
import { PrismaService } from "../prisma/prisma.service.js";
let ProductsService = class ProductsService {
prisma;
media;
audit;
revalidate;
constructor(prisma, media, audit, revalidate) {
this.prisma = prisma;
this.media = media;
this.audit = audit;
this.revalidate = revalidate;
}
async list(q) {
const where = {
...(q.categoryId && { categoryId: q.categoryId }),
...(q.groupId && { groupId: q.groupId }),
...(q.status && { isPublished: q.status === "published" }),
...(q.q && {
OR: [
{ name: { contains: q.q, mode: "insensitive" } },
{ nameEn: { contains: q.q, mode: "insensitive" } },
{ code: { contains: q.q, mode: "insensitive" } },
],
}),
};
const [rows, total] = await this.prisma.$transaction([
this.prisma.product.findMany({
where,
orderBy: [{ category: { sortOrder: "asc" } }, { sortOrder: "asc" }, { id: "asc" }],
skip: (q.page - 1) * q.pageSize,
take: q.pageSize,
include: {
image: true,
category: { select: { id: true, name: true } },
group: { select: { id: true, name: true } },
},
}),
this.prisma.product.count({ where }),
]);
return {
items: rows.map(({ image, ...p }) => ({ ...p, image: image && this.media.toDto(image) })),
total,
page: q.page,
pageSize: q.pageSize,
};
}
async get(id) {
const { image, gallery, ...p } = await this.prisma.product.findUniqueOrThrow({
where: { id },
include: { image: true, gallery: { orderBy: { sortOrder: "asc" }, include: { media: true } } },
});
return {
...p,
image: image && this.media.toDto(image),
gallery: gallery.map((g) => this.media.toDto(g.media)),
};
}
async create(input, userId) {
await this.assertGroup(input);
const { galleryIds, ...data } = input;
const last = await this.prisma.product.aggregate({
where: { categoryId: input.categoryId },
_max: { sortOrder: true },
});
const product = await this.prisma.product.create({
data: {
...data,
sortOrder: (last._max.sortOrder ?? -1) + 1,
gallery: { create: unique(galleryIds).map((mediaId, i) => ({ mediaId, sortOrder: i })) },
},
});
this.audit.log(userId, "create", "product", product.id, product.name);
this.revalidate.trigger();
return this.get(product.id);
}
async update(id, input, userId) {
await this.assertGroup(input);
const { galleryIds, ...data } = input;
const product = await this.prisma.product.update({
where: { id },
data: {
...data,
gallery: {
deleteMany: {},
create: unique(galleryIds).map((mediaId, i) => ({ mediaId, sortOrder: i })),
},
},
});
this.audit.log(userId, "update", "product", id, product.name);
this.revalidate.trigger();
return this.get(id);
}
async setPublished(id, isPublished, userId) {
const product = await this.prisma.product.update({ where: { id }, data: { isPublished } });
this.audit.log(userId, isPublished ? "publish" : "unpublish", "product", id, product.name);
this.revalidate.trigger();
return { id, isPublished };
}
async duplicate(id, userId) {
const src = await this.prisma.product.findUniqueOrThrow({
where: { id },
include: { gallery: true },
});
let n = 1;
const taken = async (code, slug) => (await this.prisma.product.count({ where: { OR: [{ code }, { slug }] } })) > 0;
while (await taken(`${src.code}-${n}`, `${src.slug}-copy-${n}`))
n++;
const copy = await this.prisma.product.create({
data: {
categoryId: src.categoryId,
groupId: src.groupId,
code: `${src.code}-${n}`,
slug: `${src.slug}-copy-${n}`,
name: `${src.name} (کپی)`,
nameEn: src.nameEn,
desc: src.desc,
specs: src.specs,
variants: src.variants,
details: src.details,
brand: src.brand,
origin: src.origin,
sizes: src.sizes,
standards: src.standards,
features: src.features,
applications: src.applications,
attributes: (src.attributes ?? []),
packaging: src.packaging,
minOrder: src.minOrder,
seoTitle: src.seoTitle,
seoDescription: src.seoDescription,
imageId: src.imageId,
sortOrder: src.sortOrder + 1,
isPublished: false,
gallery: {
create: src.gallery.map((g) => ({ mediaId: g.mediaId, sortOrder: g.sortOrder })),
},
},
});
this.audit.log(userId, "duplicate", "product", copy.id, copy.name);
return this.get(copy.id);
}
async remove(id, userId) {
const product = await this.prisma.product.delete({ where: { id } });
this.audit.log(userId, "delete", "product", id, product.name);
this.revalidate.trigger();
}
async reorder(ids, userId) {
await this.prisma.$transaction(ids.map((id, i) => this.prisma.product.update({ where: { id }, data: { sortOrder: i } })));
this.audit.log(userId, "reorder", "product", "", `${ids.length} محصول`);
this.revalidate.trigger();
}
async assertGroup(input) {
if (!input.groupId)
return;
const group = await this.prisma.productGroup.findUnique({ where: { id: input.groupId } });
if (group?.categoryId !== input.categoryId) {
throw new BadRequestException("زیرگروه انتخاب‌شده متعلق به این دسته نیست");
}
}
};
ProductsService = __decorate([
Injectable(),
__metadata("design:paramtypes", [PrismaService,
MediaService,
AuditService,
RevalidateService])
], ProductsService);
export { ProductsService };
const unique = (ids) => [...new Set(ids)];
//# sourceMappingURL=products.service.js.map
File diff suppressed because one or more lines are too long