test commit
This commit is contained in:
@@ -1,59 +1,80 @@
|
||||
import { prisma } from '../../lib/prisma.js'
|
||||
import { canTransitionAdminOrderStatus } from '../../lib/order-status.js'
|
||||
import { NOTIFICATION_EVENTS } from '../../shared/constants/notification-events.js'
|
||||
import { prisma } from "../../lib/prisma.js";
|
||||
import { canTransitionAdminOrderStatus } from "../../lib/order-status.js";
|
||||
import { NOTIFICATION_EVENTS } from "../../../../shared/constants/notification-events.js";
|
||||
|
||||
export async function registerAdminOrderRoutes(fastify) {
|
||||
fastify.get(
|
||||
'/api/admin/orders/summary',
|
||||
"/api/admin/orders/summary",
|
||||
{ preHandler: [fastify.verifyAdmin] },
|
||||
async () => {
|
||||
const attentionCount = await prisma.order.count({
|
||||
where: {
|
||||
status: 'PENDING_PAYMENT',
|
||||
status: "PENDING_PAYMENT",
|
||||
},
|
||||
})
|
||||
return { attentionCount }
|
||||
});
|
||||
return { attentionCount };
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
fastify.get(
|
||||
'/api/admin/orders',
|
||||
"/api/admin/orders",
|
||||
{ preHandler: [fastify.verifyAdmin] },
|
||||
async (request, reply) => {
|
||||
const status = typeof request.query?.status === 'string' ? request.query.status.trim() : ''
|
||||
const q = typeof request.query?.q === 'string' ? request.query.q.trim() : ''
|
||||
const deliveryTypeRaw = request.query?.deliveryType
|
||||
const deliveryType = typeof deliveryTypeRaw === 'string' ? deliveryTypeRaw.trim() : ''
|
||||
const status =
|
||||
typeof request.query?.status === "string"
|
||||
? request.query.status.trim()
|
||||
: "";
|
||||
const q =
|
||||
typeof request.query?.q === "string" ? request.query.q.trim() : "";
|
||||
const deliveryTypeRaw = request.query?.deliveryType;
|
||||
const deliveryType =
|
||||
typeof deliveryTypeRaw === "string" ? deliveryTypeRaw.trim() : "";
|
||||
|
||||
const pageRaw = request.query?.page
|
||||
const pageParsed = typeof pageRaw === 'string' ? Number(pageRaw) : Number(pageRaw)
|
||||
const page = Number.isFinite(pageParsed) && pageParsed > 0 ? Math.floor(pageParsed) : 1
|
||||
const pageRaw = request.query?.page;
|
||||
const pageParsed =
|
||||
typeof pageRaw === "string" ? Number(pageRaw) : Number(pageRaw);
|
||||
const page =
|
||||
Number.isFinite(pageParsed) && pageParsed > 0
|
||||
? Math.floor(pageParsed)
|
||||
: 1;
|
||||
|
||||
const pageSizeRaw = request.query?.pageSize
|
||||
const pageSizeParsed = typeof pageSizeRaw === 'string' ? Number(pageSizeRaw) : Number(pageSizeRaw)
|
||||
const pageSize = Number.isFinite(pageSizeParsed) && pageSizeParsed > 0 ? Math.floor(pageSizeParsed) : 20
|
||||
if (pageSize > 100) return reply.code(400).send({ error: 'pageSize должен быть ≤ 100' })
|
||||
const pageSizeRaw = request.query?.pageSize;
|
||||
const pageSizeParsed =
|
||||
typeof pageSizeRaw === "string"
|
||||
? Number(pageSizeRaw)
|
||||
: Number(pageSizeRaw);
|
||||
const pageSize =
|
||||
Number.isFinite(pageSizeParsed) && pageSizeParsed > 0
|
||||
? Math.floor(pageSizeParsed)
|
||||
: 20;
|
||||
if (pageSize > 100)
|
||||
return reply.code(400).send({ error: "pageSize должен быть ≤ 100" });
|
||||
|
||||
const where = {}
|
||||
if (status) where.status = status
|
||||
const where = {};
|
||||
if (status) where.status = status;
|
||||
if (deliveryType) {
|
||||
if (deliveryType !== 'delivery' && deliveryType !== 'pickup') {
|
||||
return reply.code(400).send({ error: 'deliveryType должен быть delivery | pickup' })
|
||||
if (deliveryType !== "delivery" && deliveryType !== "pickup") {
|
||||
return reply
|
||||
.code(400)
|
||||
.send({ error: "deliveryType должен быть delivery | pickup" });
|
||||
}
|
||||
where.deliveryType = deliveryType
|
||||
where.deliveryType = deliveryType;
|
||||
}
|
||||
if (q) {
|
||||
where.OR = [{ id: { contains: q } }, { user: { email: { contains: q } } }]
|
||||
where.OR = [
|
||||
{ id: { contains: q } },
|
||||
{ user: { email: { contains: q } } },
|
||||
];
|
||||
}
|
||||
|
||||
const total = await prisma.order.count({ where })
|
||||
const total = await prisma.order.count({ where });
|
||||
const items = await prisma.order.findMany({
|
||||
where,
|
||||
include: { user: { select: { id: true, email: true } }, items: true },
|
||||
orderBy: { createdAt: 'desc' },
|
||||
orderBy: { createdAt: "desc" },
|
||||
skip: (page - 1) * pageSize,
|
||||
take: pageSize,
|
||||
})
|
||||
});
|
||||
|
||||
return {
|
||||
items: items.map((o) => ({
|
||||
@@ -72,74 +93,97 @@ export async function registerAdminOrderRoutes(fastify) {
|
||||
total,
|
||||
page,
|
||||
pageSize,
|
||||
}
|
||||
};
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
fastify.get(
|
||||
'/api/admin/orders/:id',
|
||||
"/api/admin/orders/:id",
|
||||
{ preHandler: [fastify.verifyAdmin] },
|
||||
async (request, reply) => {
|
||||
const { id } = request.params
|
||||
const { id } = request.params;
|
||||
const order = await prisma.order.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
user: { select: { id: true, email: true, name: true, phone: true } },
|
||||
items: true,
|
||||
messages: { orderBy: { createdAt: 'asc' } },
|
||||
messages: { orderBy: { createdAt: "asc" } },
|
||||
},
|
||||
})
|
||||
if (!order) return reply.code(404).send({ error: 'Заказ не найден' })
|
||||
return { item: order }
|
||||
});
|
||||
if (!order) return reply.code(404).send({ error: "Заказ не найден" });
|
||||
return { item: order };
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
fastify.patch(
|
||||
'/api/admin/orders/:id/status',
|
||||
"/api/admin/orders/:id/status",
|
||||
{ preHandler: [fastify.verifyAdmin] },
|
||||
async (request, reply) => {
|
||||
const { id } = request.params
|
||||
const next = String(request.body?.status || '').trim()
|
||||
if (!next) return reply.code(400).send({ error: 'status обязателен' })
|
||||
const { id } = request.params;
|
||||
const next = String(request.body?.status || "").trim();
|
||||
if (!next) return reply.code(400).send({ error: "status обязателен" });
|
||||
|
||||
const existing = await prisma.order.findUnique({ where: { id } })
|
||||
if (!existing) return reply.code(404).send({ error: 'Заказ не найден' })
|
||||
const existing = await prisma.order.findUnique({ where: { id } });
|
||||
if (!existing) return reply.code(404).send({ error: "Заказ не найден" });
|
||||
if (!canTransitionAdminOrderStatus(existing, next)) {
|
||||
return reply.code(409).send({ error: `Нельзя сменить статус ${existing.status} → ${next}` })
|
||||
return reply
|
||||
.code(409)
|
||||
.send({
|
||||
error: `Нельзя сменить статус ${existing.status} → ${next}`,
|
||||
});
|
||||
}
|
||||
|
||||
const updated = await prisma.order.update({ where: { id }, data: { status: next } })
|
||||
const updated = await prisma.order.update({
|
||||
where: { id },
|
||||
data: { status: next },
|
||||
});
|
||||
|
||||
request.server.eventBus.emit(NOTIFICATION_EVENTS.ORDER_STATUS_CHANGED, {
|
||||
orderId: updated.id,
|
||||
userId: existing.userId,
|
||||
oldStatus: existing.status,
|
||||
newStatus: next,
|
||||
})
|
||||
});
|
||||
|
||||
return { item: updated }
|
||||
return { item: updated };
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
fastify.patch(
|
||||
'/api/admin/orders/:id/delivery-fee',
|
||||
"/api/admin/orders/:id/delivery-fee",
|
||||
{ preHandler: [fastify.verifyAdmin] },
|
||||
async (request, reply) => {
|
||||
const { id } = request.params
|
||||
const feeRaw = request.body?.deliveryFeeCents
|
||||
const { id } = request.params;
|
||||
const feeRaw = request.body?.deliveryFeeCents;
|
||||
const parsed =
|
||||
typeof feeRaw === 'string' ? Number.parseInt(feeRaw, 10) : typeof feeRaw === 'number' ? feeRaw : NaN
|
||||
typeof feeRaw === "string"
|
||||
? Number.parseInt(feeRaw, 10)
|
||||
: typeof feeRaw === "number"
|
||||
? feeRaw
|
||||
: NaN;
|
||||
if (!Number.isInteger(parsed) || parsed < 0) {
|
||||
return reply.code(400).send({ error: 'deliveryFeeCents должно быть целым числом ≥ 0 (копейки)' })
|
||||
return reply
|
||||
.code(400)
|
||||
.send({
|
||||
error: "deliveryFeeCents должно быть целым числом ≥ 0 (копейки)",
|
||||
});
|
||||
}
|
||||
|
||||
const existing = await prisma.order.findUnique({ where: { id } })
|
||||
if (!existing) return reply.code(404).send({ error: 'Заказ не найден' })
|
||||
if (existing.status !== 'PENDING_PAYMENT' || existing.deliveryFeeLocked !== false) {
|
||||
return reply.code(409).send({ error: 'Корректировка доставки доступна только пока стоимость не утверждена' })
|
||||
const existing = await prisma.order.findUnique({ where: { id } });
|
||||
if (!existing) return reply.code(404).send({ error: "Заказ не найден" });
|
||||
if (
|
||||
existing.status !== "PENDING_PAYMENT" ||
|
||||
existing.deliveryFeeLocked !== false
|
||||
) {
|
||||
return reply
|
||||
.code(409)
|
||||
.send({
|
||||
error:
|
||||
"Корректировка доставки доступна только пока стоимость не утверждена",
|
||||
});
|
||||
}
|
||||
|
||||
const totalCents = existing.itemsSubtotalCents + parsed
|
||||
const totalCents = existing.itemsSubtotalCents + parsed;
|
||||
const updated = await prisma.order.update({
|
||||
where: { id },
|
||||
data: {
|
||||
@@ -147,34 +191,39 @@ export async function registerAdminOrderRoutes(fastify) {
|
||||
totalCents,
|
||||
deliveryFeeLocked: true,
|
||||
},
|
||||
})
|
||||
return { item: updated }
|
||||
});
|
||||
return { item: updated };
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
fastify.post(
|
||||
'/api/admin/orders/:id/messages',
|
||||
"/api/admin/orders/:id/messages",
|
||||
{ preHandler: [fastify.verifyAdmin] },
|
||||
async (request, reply) => {
|
||||
const { id } = request.params
|
||||
const text = String(request.body?.text || '').trim()
|
||||
if (!text) return reply.code(400).send({ error: 'Сообщение пустое' })
|
||||
if (text.length > 2000) return reply.code(400).send({ error: 'Сообщение слишком длинное' })
|
||||
const { id } = request.params;
|
||||
const text = String(request.body?.text || "").trim();
|
||||
if (!text) return reply.code(400).send({ error: "Сообщение пустое" });
|
||||
if (text.length > 2000)
|
||||
return reply.code(400).send({ error: "Сообщение слишком длинное" });
|
||||
|
||||
const order = await prisma.order.findUnique({ where: { id } })
|
||||
if (!order) return reply.code(404).send({ error: 'Заказ не найден' })
|
||||
const order = await prisma.order.findUnique({ where: { id } });
|
||||
if (!order) return reply.code(404).send({ error: "Заказ не найден" });
|
||||
|
||||
const msg = await prisma.orderMessage.create({ data: { orderId: id, authorType: 'admin', text } })
|
||||
const msg = await prisma.orderMessage.create({
|
||||
data: { orderId: id, authorType: "admin", text },
|
||||
});
|
||||
|
||||
request.server.eventBus.emit(NOTIFICATION_EVENTS.ORDER_MESSAGE_ADMIN_REPLY, {
|
||||
orderId: id,
|
||||
userId: order.userId,
|
||||
messageId: msg.id,
|
||||
preview: text,
|
||||
})
|
||||
request.server.eventBus.emit(
|
||||
NOTIFICATION_EVENTS.ORDER_MESSAGE_ADMIN_REPLY,
|
||||
{
|
||||
orderId: id,
|
||||
userId: order.userId,
|
||||
messageId: msg.id,
|
||||
preview: text,
|
||||
},
|
||||
);
|
||||
|
||||
return reply.code(201).send({ item: msg })
|
||||
return reply.code(201).send({ item: msg });
|
||||
},
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,72 +1,90 @@
|
||||
import { prisma } from '../../lib/prisma.js'
|
||||
import { NOTIFICATION_EVENTS } from '../../shared/constants/notification-events.js'
|
||||
import { prisma } from "../../lib/prisma.js";
|
||||
import { NOTIFICATION_EVENTS } from "../../../../shared/constants/notification-events.js";
|
||||
|
||||
export async function registerAdminReviewRoutes(fastify) {
|
||||
fastify.get(
|
||||
'/api/admin/reviews',
|
||||
"/api/admin/reviews",
|
||||
{ preHandler: [fastify.verifyAdmin] },
|
||||
async (request, reply) => {
|
||||
const status = typeof request.query?.status === 'string' ? request.query.status.trim() : 'pending'
|
||||
const status =
|
||||
typeof request.query?.status === "string"
|
||||
? request.query.status.trim()
|
||||
: "pending";
|
||||
|
||||
const pageRaw = request.query?.page
|
||||
const pageParsed = typeof pageRaw === 'string' ? Number(pageRaw) : Number(pageRaw)
|
||||
const page = Number.isFinite(pageParsed) && pageParsed > 0 ? Math.floor(pageParsed) : 1
|
||||
const pageRaw = request.query?.page;
|
||||
const pageParsed =
|
||||
typeof pageRaw === "string" ? Number(pageRaw) : Number(pageRaw);
|
||||
const page =
|
||||
Number.isFinite(pageParsed) && pageParsed > 0
|
||||
? Math.floor(pageParsed)
|
||||
: 1;
|
||||
|
||||
const pageSizeRaw = request.query?.pageSize
|
||||
const pageSizeParsed = typeof pageSizeRaw === 'string' ? Number(pageSizeRaw) : Number(pageSizeRaw)
|
||||
const pageSize = Number.isFinite(pageSizeParsed) && pageSizeParsed > 0 ? Math.floor(pageSizeParsed) : 20
|
||||
if (pageSize > 100) return reply.code(400).send({ error: 'pageSize должен быть ≤ 100' })
|
||||
const pageSizeRaw = request.query?.pageSize;
|
||||
const pageSizeParsed =
|
||||
typeof pageSizeRaw === "string"
|
||||
? Number(pageSizeRaw)
|
||||
: Number(pageSizeRaw);
|
||||
const pageSize =
|
||||
Number.isFinite(pageSizeParsed) && pageSizeParsed > 0
|
||||
? Math.floor(pageSizeParsed)
|
||||
: 20;
|
||||
if (pageSize > 100)
|
||||
return reply.code(400).send({ error: "pageSize должен быть ≤ 100" });
|
||||
|
||||
const where = status ? { status } : {}
|
||||
const total = await prisma.review.count({ where })
|
||||
const where = status ? { status } : {};
|
||||
const total = await prisma.review.count({ where });
|
||||
const items = await prisma.review.findMany({
|
||||
where,
|
||||
include: {
|
||||
user: { select: { id: true, email: true, name: true } },
|
||||
product: { select: { id: true, title: true } },
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
orderBy: { createdAt: "desc" },
|
||||
skip: (page - 1) * pageSize,
|
||||
take: pageSize,
|
||||
})
|
||||
});
|
||||
|
||||
return { items, total, page, pageSize }
|
||||
return { items, total, page, pageSize };
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
fastify.patch(
|
||||
'/api/admin/reviews/:id',
|
||||
"/api/admin/reviews/:id",
|
||||
{ preHandler: [fastify.verifyAdmin] },
|
||||
async (request, reply) => {
|
||||
const { id } = request.params
|
||||
const action = String(request.body?.action || '').trim()
|
||||
if (action !== 'approve' && action !== 'reject') {
|
||||
return reply.code(400).send({ error: 'action должен быть approve или reject' })
|
||||
const { id } = request.params;
|
||||
const action = String(request.body?.action || "").trim();
|
||||
if (action !== "approve" && action !== "reject") {
|
||||
return reply
|
||||
.code(400)
|
||||
.send({ error: "action должен быть approve или reject" });
|
||||
}
|
||||
|
||||
const existing = await prisma.review.findUnique({
|
||||
where: { id },
|
||||
include: { product: { select: { title: true } }, user: { select: { name: true, email: true } } },
|
||||
})
|
||||
if (!existing) return reply.code(404).send({ error: 'Отзыв не найден' })
|
||||
include: {
|
||||
product: { select: { title: true } },
|
||||
user: { select: { name: true, email: true } },
|
||||
},
|
||||
});
|
||||
if (!existing) return reply.code(404).send({ error: "Отзыв не найден" });
|
||||
|
||||
const updated = await prisma.review.update({
|
||||
where: { id },
|
||||
data: {
|
||||
status: action === 'approve' ? 'approved' : 'rejected',
|
||||
status: action === "approve" ? "approved" : "rejected",
|
||||
moderatedAt: new Date(),
|
||||
},
|
||||
})
|
||||
request.server.eventBus.emit('review:created', {
|
||||
});
|
||||
request.server.eventBus.emit("review:created", {
|
||||
rating: updated.rating,
|
||||
text: updated.text || '',
|
||||
productTitle: existing.product?.title || '',
|
||||
userName: existing.user?.name || existing.user?.email || '',
|
||||
text: updated.text || "",
|
||||
productTitle: existing.product?.title || "",
|
||||
userName: existing.user?.name || existing.user?.email || "",
|
||||
reviewId: updated.id,
|
||||
})
|
||||
});
|
||||
|
||||
return { item: updated }
|
||||
return { item: updated };
|
||||
},
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { prisma } from '../../lib/prisma.js'
|
||||
import { prisma } from "../../../lib/prisma.js";
|
||||
|
||||
export async function registerAdminNotificationRoutes(fastify) {
|
||||
fastify.get(
|
||||
'/api/admin/notifications/settings',
|
||||
"/api/admin/notifications/settings",
|
||||
{ preHandler: [fastify.verifyAdmin] },
|
||||
async () => {
|
||||
let settings = await prisma.adminNotificationSettings.findFirst()
|
||||
let settings = await prisma.adminNotificationSettings.findFirst();
|
||||
if (!settings) {
|
||||
settings = await prisma.adminNotificationSettings.create({
|
||||
data: {
|
||||
@@ -16,74 +16,80 @@ export async function registerAdminNotificationRoutes(fastify) {
|
||||
newReview: true,
|
||||
authCodeDuplicate: false,
|
||||
},
|
||||
})
|
||||
});
|
||||
}
|
||||
return { settings }
|
||||
return { settings };
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
fastify.put(
|
||||
'/api/admin/notifications/settings',
|
||||
"/api/admin/notifications/settings",
|
||||
{ preHandler: [fastify.verifyAdmin] },
|
||||
async (request) => {
|
||||
const body = request.body || {}
|
||||
let settings = await prisma.adminNotificationSettings.findFirst()
|
||||
const body = request.body || {};
|
||||
let settings = await prisma.adminNotificationSettings.findFirst();
|
||||
|
||||
const data = {}
|
||||
if ('emailEnabled' in body) data.emailEnabled = Boolean(body.emailEnabled)
|
||||
if ('telegramEnabled' in body) data.telegramEnabled = Boolean(body.telegramEnabled)
|
||||
if ('telegramChatId' in body) data.telegramChatId = body.telegramChatId || null
|
||||
if ('newOrder' in body) data.newOrder = Boolean(body.newOrder)
|
||||
if ('newOrderMessage' in body) data.newOrderMessage = Boolean(body.newOrderMessage)
|
||||
if ('newReview' in body) data.newReview = Boolean(body.newReview)
|
||||
if ('authCodeDuplicate' in body) data.authCodeDuplicate = Boolean(body.authCodeDuplicate)
|
||||
const data = {};
|
||||
if ("emailEnabled" in body)
|
||||
data.emailEnabled = Boolean(body.emailEnabled);
|
||||
if ("telegramEnabled" in body)
|
||||
data.telegramEnabled = Boolean(body.telegramEnabled);
|
||||
if ("telegramChatId" in body)
|
||||
data.telegramChatId = body.telegramChatId || null;
|
||||
if ("newOrder" in body) data.newOrder = Boolean(body.newOrder);
|
||||
if ("newOrderMessage" in body)
|
||||
data.newOrderMessage = Boolean(body.newOrderMessage);
|
||||
if ("newReview" in body) data.newReview = Boolean(body.newReview);
|
||||
if ("authCodeDuplicate" in body)
|
||||
data.authCodeDuplicate = Boolean(body.authCodeDuplicate);
|
||||
|
||||
if (!settings) {
|
||||
settings = await prisma.adminNotificationSettings.create({ data })
|
||||
settings = await prisma.adminNotificationSettings.create({ data });
|
||||
} else {
|
||||
settings = await prisma.adminNotificationSettings.update({
|
||||
where: { id: settings.id },
|
||||
data,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
return { settings }
|
||||
return { settings };
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
fastify.post(
|
||||
'/api/admin/notifications/telegram/webhook',
|
||||
async (request) => {
|
||||
const update = request.body || {}
|
||||
const message = update.message
|
||||
if (!message || !message.text || message.text !== '/start') return { ok: true }
|
||||
fastify.post("/api/admin/notifications/telegram/webhook", async (request) => {
|
||||
const update = request.body || {};
|
||||
const message = update.message;
|
||||
if (!message || !message.text || message.text !== "/start")
|
||||
return { ok: true };
|
||||
|
||||
const chatId = String(message.chat.id)
|
||||
const settings = await prisma.adminNotificationSettings.findFirst()
|
||||
const chatId = String(message.chat.id);
|
||||
const settings = await prisma.adminNotificationSettings.findFirst();
|
||||
|
||||
if (settings) {
|
||||
await prisma.adminNotificationSettings.update({
|
||||
where: { id: settings.id },
|
||||
data: { telegramChatId: chatId },
|
||||
})
|
||||
} else {
|
||||
await prisma.adminNotificationSettings.create({
|
||||
data: { telegramChatId: chatId },
|
||||
})
|
||||
}
|
||||
if (settings) {
|
||||
await prisma.adminNotificationSettings.update({
|
||||
where: { id: settings.id },
|
||||
data: { telegramChatId: chatId },
|
||||
});
|
||||
} else {
|
||||
await prisma.adminNotificationSettings.create({
|
||||
data: { telegramChatId: chatId },
|
||||
});
|
||||
}
|
||||
|
||||
if (process.env.TELEGRAM_BOT_TOKEN) {
|
||||
await fetch(`https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendMessage`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
if (process.env.TELEGRAM_BOT_TOKEN) {
|
||||
await fetch(
|
||||
`https://api.telegram.org/bot${process.env.TELEGRAM_BOT_TOKEN}/sendMessage`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
chat_id: chatId,
|
||||
text: 'Вы подписаны на уведомления Craftshop.',
|
||||
text: "Вы подписаны на уведомления Любимый Креатив.",
|
||||
}),
|
||||
})
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return { ok: true }
|
||||
},
|
||||
)
|
||||
return { ok: true };
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user