Новые правки компонентов
This commit is contained in:
parent
ddc0a26635
commit
189768971d
7 changed files with 549 additions and 589 deletions
|
|
@ -1,6 +1,8 @@
|
|||
import type { APIRoute } from "astro";
|
||||
import { sendEmail } from "../../../lib/email";
|
||||
|
||||
const POCKETBASE_URL = import.meta.env.POCKETBASE_URL || "http://localhost:8090";
|
||||
const ADMIN_EMAIL = import.meta.env.PB_ADMIN_EMAIL || "redibedi2019@gmail.com";
|
||||
|
||||
export const POST: APIRoute = async ({ request, cookies }) => {
|
||||
const pbAuthCookie = cookies.get("pb_auth")?.value;
|
||||
|
|
@ -75,7 +77,7 @@ export const POST: APIRoute = async ({ request, cookies }) => {
|
|||
profession,
|
||||
rating,
|
||||
text,
|
||||
status: "pending",
|
||||
status: "published",
|
||||
votesCount: 0,
|
||||
user: userId,
|
||||
}),
|
||||
|
|
@ -91,6 +93,32 @@ export const POST: APIRoute = async ({ request, cookies }) => {
|
|||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await sendEmail({
|
||||
to: ADMIN_EMAIL,
|
||||
subject: `Новый отзыв на сайте: ${rating} звёзд от ${name} ${surname}`,
|
||||
html: `
|
||||
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
|
||||
<h2 style="color: #1e3050;">Новый отзыв на сайте</h2>
|
||||
<div style="background: #f8fafc; padding: 20px; border-radius: 12px; margin: 20px 0;">
|
||||
<p><strong>Автор:</strong> ${name} ${surname}</p>
|
||||
<p><strong>Профессия:</strong> ${profession}</p>
|
||||
<p><strong>Оценка:</strong> ${"⭐".repeat(rating)} (${rating}/5)</p>
|
||||
<p><strong>Дата:</strong> ${new Date().toLocaleDateString("ru-RU")}</p>
|
||||
</div>
|
||||
<div style="background: #ffffff; padding: 20px; border: 1px solid #e2e8f0; border-radius: 12px;">
|
||||
<p style="margin: 0; line-height: 1.6;">${text}</p>
|
||||
</div>
|
||||
<p style="color: #64748b; font-size: 14px; margin-top: 20px;">
|
||||
Это письмо отправлено автоматически с сайта avtourist-surgut.ru
|
||||
</p>
|
||||
</div>
|
||||
`,
|
||||
});
|
||||
} catch (emailError) {
|
||||
console.error("[Reviews API] Email error:", emailError);
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify(data), {
|
||||
status: 201,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type { APIRoute } from 'astro';
|
|||
|
||||
const POCKETBASE_URL = import.meta.env.POCKETBASE_URL || 'http://127.0.0.1:8090';
|
||||
|
||||
const POCKETBASE_ID_REGEX = /^[a-z0-9]{15}$/;
|
||||
const PB_ID_REGEX = /^[a-z0-9]{15}$/;
|
||||
|
||||
export const POST: APIRoute = async ({ request, cookies }) => {
|
||||
try {
|
||||
|
|
@ -28,7 +28,7 @@ export const POST: APIRoute = async ({ request, cookies }) => {
|
|||
|
||||
if (!authResponse.ok) {
|
||||
return new Response(
|
||||
JSON.stringify({ error: 'Недействительная сессия' }),
|
||||
JSON.stringify({ error: 'Нед<EFBFBD><EFBFBD>йствительная сессия' }),
|
||||
{ status: 401, headers: { 'Content-Type': 'application/json' } }
|
||||
);
|
||||
}
|
||||
|
|
@ -36,9 +36,9 @@ export const POST: APIRoute = async ({ request, cookies }) => {
|
|||
const authData = await authResponse.json();
|
||||
const userId = authData.record?.id;
|
||||
|
||||
if (!userId || !POCKETBASE_ID_REGEX.test(userId)) {
|
||||
if (!userId || !PB_ID_REGEX.test(userId)) {
|
||||
return new Response(
|
||||
JSON.stringify({ error: 'Ошибка идентификации пользователя' }),
|
||||
JSON.stringify({ error: 'Ошибка идентификации' }),
|
||||
{ status: 500, headers: { 'Content-Type': 'application/json' } }
|
||||
);
|
||||
}
|
||||
|
|
@ -46,14 +46,14 @@ export const POST: APIRoute = async ({ request, cookies }) => {
|
|||
const body = await request.json();
|
||||
const { review_id, vote_type } = body;
|
||||
|
||||
if (!review_id || !POCKETBASE_ID_REGEX.test(review_id)) {
|
||||
if (!review_id || !PB_ID_REGEX.test(review_id)) {
|
||||
return new Response(
|
||||
JSON.stringify({ error: 'Некорректный review_id' }),
|
||||
{ status: 400, headers: { 'Content-Type': 'application/json' } }
|
||||
);
|
||||
}
|
||||
|
||||
if (!vote_type || !['like', 'dislike'].includes(vote_type)) {
|
||||
if (!vote_type || !['likes', 'dislikes'].includes(vote_type)) {
|
||||
return new Response(
|
||||
JSON.stringify({ error: 'Некорректный vote_type' }),
|
||||
{ status: 400, headers: { 'Content-Type': 'application/json' } }
|
||||
|
|
@ -61,19 +61,16 @@ export const POST: APIRoute = async ({ request, cookies }) => {
|
|||
}
|
||||
|
||||
const existingVoteRes = await fetch(
|
||||
`${POCKETBASE_URL}/api/collections/review_votes/records?` +
|
||||
new URLSearchParams({
|
||||
filter: `review="${review_id}" && user="${userId}"`,
|
||||
}),
|
||||
`${POCKETBASE_URL}/api/collections/review_votes/records?filter=(review="${review_id}")&&(user="${userId}")`,
|
||||
{
|
||||
headers: { 'Authorization': `Bearer ${token}` },
|
||||
}
|
||||
);
|
||||
|
||||
let userVote: 'likes' | 'dislikes' | null = null;
|
||||
let method = 'POST';
|
||||
let url = `${POCKETBASE_URL}/api/collections/review_votes/records`;
|
||||
let voteId = null;
|
||||
let userVote: 'like' | 'dislike' | null = null;
|
||||
let voteId: string | null = null;
|
||||
|
||||
if (existingVoteRes.ok) {
|
||||
const existingData = await existingVoteRes.json();
|
||||
|
|
@ -93,58 +90,43 @@ export const POST: APIRoute = async ({ request, cookies }) => {
|
|||
}
|
||||
|
||||
const voteBody = method === 'POST'
|
||||
? JSON.stringify({ review: review_id, user: userId, vote_type })
|
||||
? JSON.stringify({ review: review_id, user: userId, vote_type: vote_type })
|
||||
: method === 'PATCH'
|
||||
? JSON.stringify({ vote_type })
|
||||
: null;
|
||||
? JSON.stringify({ vote_type: vote_type })
|
||||
: undefined;
|
||||
|
||||
const voteRes = await fetch(url, {
|
||||
method,
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Type': method !== 'DELETE' ? 'application/json' : undefined,
|
||||
},
|
||||
body: voteBody,
|
||||
});
|
||||
|
||||
if (!voteRes.ok && method !== 'DELETE') {
|
||||
const errorText = await voteRes.text();
|
||||
console.error('[ReviewVote API] Failed to save vote:', errorText);
|
||||
console.error('[ReviewVote API] Vote error:', errorText);
|
||||
throw new Error('Failed to save vote');
|
||||
}
|
||||
|
||||
if (method === 'POST') userVote = vote_type;
|
||||
if (method === 'DELETE') userVote = null;
|
||||
|
||||
const likesRes = await fetch(
|
||||
`${POCKETBASE_URL}/api/collections/review_votes/records?` +
|
||||
new URLSearchParams({
|
||||
filter: `review="${review_id}"`,
|
||||
fields: 'vote_type',
|
||||
})
|
||||
const votesRes = await fetch(
|
||||
`${POCKETBASE_URL}/api/collections/review_votes/records?filter=(review="${review_id}")`,
|
||||
{}
|
||||
);
|
||||
|
||||
let likes = 0;
|
||||
let dislikes = 0;
|
||||
|
||||
if (likesRes.ok) {
|
||||
const votesData = await likesRes.json();
|
||||
likes = votesData.items.filter((v: any) => v.vote_type === 'like').length;
|
||||
dislikes = votesData.items.filter((v: any) => v.vote_type === 'dislike').length;
|
||||
if (votesRes.ok) {
|
||||
const votesData = await votesRes.json();
|
||||
likes = votesData.items?.filter((v: any) => v.vote_type === 'likes').length || 0;
|
||||
dislikes = votesData.items?.filter((v: any) => v.vote_type === 'dislikes').length || 0;
|
||||
}
|
||||
|
||||
await fetch(
|
||||
`${POCKETBASE_URL}/api/collections/reviews/records/${review_id}`,
|
||||
{
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ votesCount: likes }),
|
||||
}
|
||||
);
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({ likes, dislikes, userVote }),
|
||||
{ status: 200, headers: { 'Content-Type': 'application/json' } }
|
||||
|
|
@ -152,7 +134,7 @@ export const POST: APIRoute = async ({ request, cookies }) => {
|
|||
} catch (error) {
|
||||
console.error('[ReviewVote API] Error:', error);
|
||||
return new Response(
|
||||
JSON.stringify({ error: 'Внутренняя ошибка сервера' }),
|
||||
JSON.stringify({ error: 'Внутренняя ошибка' }),
|
||||
{ status: 500, headers: { 'Content-Type': 'application/json' } }
|
||||
);
|
||||
}
|
||||
|
|
@ -163,30 +145,16 @@ export const GET: APIRoute = async ({ url, cookies }) => {
|
|||
const reviewId = url.searchParams.get('review_id');
|
||||
const token = cookies.get('pb_auth')?.value;
|
||||
|
||||
if (!reviewId || !POCKETBASE_ID_REGEX.test(reviewId)) {
|
||||
if (!reviewId || !PB_ID_REGEX.test(reviewId)) {
|
||||
return new Response(
|
||||
JSON.stringify({ error: 'Некорректный review_id' }),
|
||||
{ status: 400, headers: { 'Content-Type': 'application/json' } }
|
||||
);
|
||||
}
|
||||
|
||||
const reviewRes = await fetch(
|
||||
`${POCKETBASE_URL}/api/collections/reviews/records/${reviewId}`
|
||||
);
|
||||
|
||||
if (!reviewRes.ok) {
|
||||
return new Response(
|
||||
JSON.stringify({ error: 'Отзыв не найден' }),
|
||||
{ status: 404, headers: { 'Content-Type': 'application/json' } }
|
||||
);
|
||||
}
|
||||
|
||||
const votesRes = await fetch(
|
||||
`${POCKETBASE_URL}/api/collections/review_votes/records?` +
|
||||
new URLSearchParams({
|
||||
filter: `review="${reviewId}"`,
|
||||
fields: 'vote_type',
|
||||
})
|
||||
`${POCKETBASE_URL}/api/collections/review_votes/records?filter=(review="${reviewId}")`,
|
||||
{}
|
||||
);
|
||||
|
||||
let likes = 0;
|
||||
|
|
@ -194,11 +162,11 @@ export const GET: APIRoute = async ({ url, cookies }) => {
|
|||
|
||||
if (votesRes.ok) {
|
||||
const votesData = await votesRes.json();
|
||||
likes = votesData.items.filter((v: any) => v.vote_type === 'like').length;
|
||||
dislikes = votesData.items.filter((v: any) => v.vote_type === 'dislike').length;
|
||||
likes = votesData.items?.filter((v: any) => v.vote_type === 'likes').length || 0;
|
||||
dislikes = votesData.items?.filter((v: any) => v.vote_type === 'dislikes').length || 0;
|
||||
}
|
||||
|
||||
let userVote: 'like' | 'dislike' | null = null;
|
||||
let userVote: 'likes' | 'dislikes' | null = null;
|
||||
|
||||
if (token) {
|
||||
try {
|
||||
|
|
@ -214,12 +182,9 @@ export const GET: APIRoute = async ({ url, cookies }) => {
|
|||
const authData = await authRes.json();
|
||||
const userId = authData.record?.id;
|
||||
|
||||
if (userId && POCKETBASE_ID_REGEX.test(userId)) {
|
||||
if (userId && PB_ID_REGEX.test(userId)) {
|
||||
const userVoteRes = await fetch(
|
||||
`${POCKETBASE_URL}/api/collections/review_votes/records?` +
|
||||
new URLSearchParams({
|
||||
filter: `review="${reviewId}" && user="${userId}"`,
|
||||
}),
|
||||
`${POCKETBASE_URL}/api/collections/review_votes/records?filter=(review="${reviewId}")&&(user="${userId}")`,
|
||||
{
|
||||
headers: { 'Authorization': `Bearer ${token}` },
|
||||
}
|
||||
|
|
@ -234,7 +199,7 @@ export const GET: APIRoute = async ({ url, cookies }) => {
|
|||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('[ReviewVote API] Error fetching user vote:', e);
|
||||
console.error('[ReviewVote API GET] Error:', e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -245,7 +210,7 @@ export const GET: APIRoute = async ({ url, cookies }) => {
|
|||
} catch (error) {
|
||||
console.error('[ReviewVote API GET] Error:', error);
|
||||
return new Response(
|
||||
JSON.stringify({ error: 'Внутренняя ошибка сервера' }),
|
||||
JSON.stringify({ error: 'Внутренняя ошибка' }),
|
||||
{ status: 500, headers: { 'Content-Type': 'application/json' } }
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue