191 lines
7.9 KiB
JavaScript
191 lines
7.9 KiB
JavaScript
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 { BadRequestException, Body, Controller, ForbiddenException, Get, Injectable, Module, NotFoundException, Param, Patch, Put, ServiceUnavailableException, } from "@nestjs/common";
|
||
|
|
import { isSectionKey, SECTION_KEYS, sectionSchemas, toIssues, } from "@imen/shared";
|
||
|
|
import { AdminAuth, CurrentUser } from "../common/auth.js";
|
||
|
|
import { AuditService, RevalidateService } from "../common/common.module.js";
|
||
|
|
import { PrismaService } from "../prisma/prisma.service.js";
|
||
|
|
let SectionsService = class SectionsService {
|
||
|
|
prisma;
|
||
|
|
audit;
|
||
|
|
revalidate;
|
||
|
|
constructor(prisma, audit, revalidate) {
|
||
|
|
this.prisma = prisma;
|
||
|
|
this.audit = audit;
|
||
|
|
this.revalidate = revalidate;
|
||
|
|
}
|
||
|
|
async getAll() {
|
||
|
|
const rows = await this.prisma.siteSection.findMany();
|
||
|
|
const byKey = new Map(rows.map((r) => [r.key, r.data]));
|
||
|
|
const missing = SECTION_KEYS.filter((k) => !byKey.has(k));
|
||
|
|
if (missing.length) {
|
||
|
|
throw new ServiceUnavailableException(`محتوای سایت مقداردهی نشده است (${missing.join(", ")}) — pnpm db:seed را اجرا کنید`);
|
||
|
|
}
|
||
|
|
return Object.fromEntries(SECTION_KEYS.map((k) => [k, sectionSchemas[k].parse(byKey.get(k))]));
|
||
|
|
}
|
||
|
|
async get(key) {
|
||
|
|
if (!isSectionKey(key))
|
||
|
|
throw new NotFoundException("بخش پیدا نشد");
|
||
|
|
const row = await this.prisma.siteSection.findUnique({ where: { key } });
|
||
|
|
if (!row)
|
||
|
|
throw new NotFoundException("بخش پیدا نشد");
|
||
|
|
return { key, data: sectionSchemas[key].parse(row.data), updatedAt: row.updatedAt };
|
||
|
|
}
|
||
|
|
async update(key, body, user) {
|
||
|
|
if (!isSectionKey(key))
|
||
|
|
throw new NotFoundException("بخش پیدا نشد");
|
||
|
|
if (key === "settings" && user.role !== "ADMIN") {
|
||
|
|
throw new ForbiddenException("فقط مدیر کل میتواند تنظیمات سایت را تغییر دهد");
|
||
|
|
}
|
||
|
|
const parsed = sectionSchemas[key].safeParse(body);
|
||
|
|
if (!parsed.success) {
|
||
|
|
throw new BadRequestException({
|
||
|
|
statusCode: 400,
|
||
|
|
message: "اطلاعات واردشده معتبر نیست",
|
||
|
|
issues: toIssues(parsed.error),
|
||
|
|
});
|
||
|
|
}
|
||
|
|
const row = await this.prisma.siteSection.upsert({
|
||
|
|
where: { key },
|
||
|
|
create: { key, data: parsed.data, updatedById: user.id },
|
||
|
|
update: { data: parsed.data, updatedById: user.id },
|
||
|
|
});
|
||
|
|
this.audit.log(user.id, "update", "section", key, key);
|
||
|
|
this.revalidate.trigger();
|
||
|
|
return { key, data: parsed.data, updatedAt: row.updatedAt };
|
||
|
|
}
|
||
|
|
async listAdmin() {
|
||
|
|
const rows = await this.prisma.siteSection.findMany();
|
||
|
|
const byKey = new Map(rows.map((r) => [r.key, r]));
|
||
|
|
return SECTION_KEYS.map((key) => {
|
||
|
|
const row = byKey.get(key);
|
||
|
|
let data = null;
|
||
|
|
if (row) {
|
||
|
|
const parsed = sectionSchemas[key].safeParse(row.data);
|
||
|
|
data = parsed.success ? parsed.data : row.data;
|
||
|
|
}
|
||
|
|
return {
|
||
|
|
key,
|
||
|
|
updatedAt: row?.updatedAt?.toISOString() ?? null,
|
||
|
|
enabled: data && typeof data === "object" && "enabled" in data
|
||
|
|
? data.enabled !== false
|
||
|
|
: true,
|
||
|
|
};
|
||
|
|
});
|
||
|
|
}
|
||
|
|
async setVisibility(key, enabled, user) {
|
||
|
|
if (!isSectionKey(key))
|
||
|
|
throw new NotFoundException("بخش پیدا نشد");
|
||
|
|
if (key === "settings") {
|
||
|
|
throw new BadRequestException("تنظیمات سایت قابلیت تغییر وضعیت نمایش ندارد");
|
||
|
|
}
|
||
|
|
const row = await this.prisma.siteSection.findUnique({ where: { key } });
|
||
|
|
if (!row)
|
||
|
|
throw new NotFoundException("بخش پیدا نشد");
|
||
|
|
const currentData = row.data && typeof row.data === "object" ? { ...row.data } : {};
|
||
|
|
currentData.enabled = enabled;
|
||
|
|
const parsed = sectionSchemas[key].safeParse(currentData);
|
||
|
|
if (!parsed.success) {
|
||
|
|
throw new BadRequestException({
|
||
|
|
statusCode: 400,
|
||
|
|
message: "اطلاعات بخش معتبر نیست",
|
||
|
|
issues: toIssues(parsed.error),
|
||
|
|
});
|
||
|
|
}
|
||
|
|
const updated = await this.prisma.siteSection.update({
|
||
|
|
where: { key },
|
||
|
|
data: { data: parsed.data, updatedById: user.id },
|
||
|
|
});
|
||
|
|
this.audit.log(user.id, "update", "section", key, `تغییر وضعیت نمایش به ${enabled ? "نمایش" : "عدم نمایش"}`);
|
||
|
|
this.revalidate.trigger();
|
||
|
|
return {
|
||
|
|
key,
|
||
|
|
enabled: parsed.data.enabled !== false,
|
||
|
|
updatedAt: updated.updatedAt.toISOString(),
|
||
|
|
};
|
||
|
|
}
|
||
|
|
};
|
||
|
|
SectionsService = __decorate([
|
||
|
|
Injectable(),
|
||
|
|
__metadata("design:paramtypes", [PrismaService,
|
||
|
|
AuditService,
|
||
|
|
RevalidateService])
|
||
|
|
], SectionsService);
|
||
|
|
export { SectionsService };
|
||
|
|
let SectionsController = class SectionsController {
|
||
|
|
sections;
|
||
|
|
constructor(sections) {
|
||
|
|
this.sections = sections;
|
||
|
|
}
|
||
|
|
list() {
|
||
|
|
return this.sections.listAdmin();
|
||
|
|
}
|
||
|
|
get(key) {
|
||
|
|
return this.sections.get(key);
|
||
|
|
}
|
||
|
|
update(key, body, user) {
|
||
|
|
return this.sections.update(key, body, user);
|
||
|
|
}
|
||
|
|
setVisibility(key, body, user) {
|
||
|
|
const enabled = body && typeof body.enabled === "boolean" ? body.enabled : Boolean(body?.enabled);
|
||
|
|
return this.sections.setVisibility(key, enabled, user);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
__decorate([
|
||
|
|
Get(),
|
||
|
|
__metadata("design:type", Function),
|
||
|
|
__metadata("design:paramtypes", []),
|
||
|
|
__metadata("design:returntype", void 0)
|
||
|
|
], SectionsController.prototype, "list", null);
|
||
|
|
__decorate([
|
||
|
|
Get(":key"),
|
||
|
|
__param(0, Param("key")),
|
||
|
|
__metadata("design:type", Function),
|
||
|
|
__metadata("design:paramtypes", [String]),
|
||
|
|
__metadata("design:returntype", void 0)
|
||
|
|
], SectionsController.prototype, "get", null);
|
||
|
|
__decorate([
|
||
|
|
Put(":key"),
|
||
|
|
__param(0, Param("key")),
|
||
|
|
__param(1, Body()),
|
||
|
|
__param(2, CurrentUser()),
|
||
|
|
__metadata("design:type", Function),
|
||
|
|
__metadata("design:paramtypes", [String, Object, Object]),
|
||
|
|
__metadata("design:returntype", void 0)
|
||
|
|
], SectionsController.prototype, "update", null);
|
||
|
|
__decorate([
|
||
|
|
Patch(":key/visibility"),
|
||
|
|
__param(0, Param("key")),
|
||
|
|
__param(1, Body()),
|
||
|
|
__param(2, CurrentUser()),
|
||
|
|
__metadata("design:type", Function),
|
||
|
|
__metadata("design:paramtypes", [String, Object, Object]),
|
||
|
|
__metadata("design:returntype", void 0)
|
||
|
|
], SectionsController.prototype, "setVisibility", null);
|
||
|
|
SectionsController = __decorate([
|
||
|
|
AdminAuth(),
|
||
|
|
Controller("admin/sections"),
|
||
|
|
__metadata("design:paramtypes", [SectionsService])
|
||
|
|
], SectionsController);
|
||
|
|
export { SectionsController };
|
||
|
|
let SectionsModule = class SectionsModule {
|
||
|
|
};
|
||
|
|
SectionsModule = __decorate([
|
||
|
|
Module({
|
||
|
|
controllers: [SectionsController],
|
||
|
|
providers: [SectionsService],
|
||
|
|
exports: [SectionsService],
|
||
|
|
})
|
||
|
|
], SectionsModule);
|
||
|
|
export { SectionsModule };
|
||
|
|
//# sourceMappingURL=sections.module.js.map
|