diff --git a/src/routes/articles/controllers/crud.ts b/src/routes/articles/controllers/crud.ts index 852ea2a..c09f3a4 100644 --- a/src/routes/articles/controllers/crud.ts +++ b/src/routes/articles/controllers/crud.ts @@ -3,6 +3,9 @@ import { prisma } from '../../../lib/prisma'; import { AuthRequest } from '../../../middleware/auth'; import { checkPermission } from '../../../utils/permissions'; import { logger } from '../../../config/logger'; +import { Article } from "../../../types"; + +const DEFAULT_COVER_IMAGE = 'https://images.unsplash.com/photo-1460661419201-fd4cecdf8a8b?auto=format&fit=crop&q=80&w=2070'; export async function getArticle(req: Request, res: Response) : Promise { try { @@ -38,20 +41,20 @@ export async function createArticle(req: AuthRequest, res: Response) : Promise 8) { - logger.warn(`Invalid category ID: ${categoryId}`); - res.status(400).json({ error: 'Invalid category' }); + logger.warn(`Недопустимый ID категории: ${categoryId}`); + res.status(400).json({ error: 'Недопустимая категория' }); return } if (!checkPermission(req.user, categoryId, 'create')) { - logger.warn(`Permission denied for user ${req.user.id} to create article in category ${categoryId}`); - res.status(403).json({ error: 'Permission denied' }); + logger.warn(`Не разрешено для пользователя ${req.user.id} создавать статьи в категории ${categoryId}`); + res.status(403).json({ error: 'В разрешении отказано' }); return } @@ -77,11 +80,11 @@ export async function createArticle(req: AuthRequest, res: Response) : Promise { try { if (!req.user) { - res.status(401).json({ error: 'Not authenticated' }); + res.status(401).json({ error: 'Пользователь не вошел в систему' }); return } @@ -149,22 +152,75 @@ export async function deleteArticle(req: AuthRequest, res: Response) : Promise { + const articles: Article[] = req.body; + + if (!Array.isArray(articles) || articles.length === 0) { + res.status(400).json({ message: 'Ожидается непустой массив статей в теле запроса' }); + return + } + + let importedCount = 0; + + try { + for (const article of articles) { + try { + // Шаг 1: Создание статьи + const newArticle = await prisma.article.create({ + data: { + title: article.title, + excerpt: article.excerpt, + content: article.content, + categoryId: article.categoryId, + cityId: article.cityId, + coverImage: DEFAULT_COVER_IMAGE, + readTime: article.readTime, + publishedAt: new Date(article.publishedAt), + likes: article.likes || 0, + dislikes: article.dislikes || 0, + author: { + connect: { id: article.author.id }, + }, + }, + }); + + // Шаг 2: Обработка coverImage + + + importedCount++; + } catch (articleError) { + console.error(`Ошибка импорта статьи ${article.id}:`, articleError); + } + } + + res.status(200).json({ + message: `Импорт завершен. Успешно импортировано ${importedCount} из ${articles.length} статей.`, + }); + } catch (err) { + console.error('Ошибка обработки запроса:', err); + res.status(500).json({ message: 'Ошибка сервера при импорте' }); + } finally { + await prisma.$disconnect(); + } +} + diff --git a/src/routes/articles/controllers/list.ts b/src/routes/articles/controllers/list.ts index 08869f3..75cf607 100644 --- a/src/routes/articles/controllers/list.ts +++ b/src/routes/articles/controllers/list.ts @@ -2,23 +2,25 @@ import { Request, Response } from 'express'; import { prisma } from '../../../lib/prisma'; import { Prisma } from '@prisma/client'; + export async function listArticles(req: Request, res: Response) { try { - const { page = 1, categoryId, cityId } = req.query; + let page = Number(req.query.page); + if (!Number.isInteger(page) || page < 1) page = 1; // Гарантируем, что `page` - корректное число + const perPage = 6; - // Преобразование и проверка параметров - const catId = Number(categoryId); - const citId = Number(cityId); + // Преобразование и проверка categoryId и cityId + const catId = Number(req.query.categoryId); + const citId = Number(req.query.cityId); - // Проверка и преобразование параметров const where: Prisma.ArticleWhereInput = { - ...(categoryId && !Number.isNaN(catId) && catId !== 0 && { categoryId: catId }), - ...(cityId && !Number.isNaN(citId) && citId !== 0 && { cityId: citId }), + ...(Number.isInteger(catId) && catId > 0 ? { categoryId: catId } : {}), + ...(Number.isInteger(citId) && citId > 0 ? { cityId: citId } : {}), }; - // Рассчитываем пропуск записей для пагинации - const skip = (Number(page) - 1) * perPage; + // Рассчитываем пропуск записей + const skip = (page - 1) * perPage; // Выполняем два параллельных запроса: получение статей и подсчёт общего количества const [articles, total] = await Promise.all([ @@ -45,7 +47,7 @@ export async function listArticles(req: Request, res: Response) { res.json({ articles, totalPages: Math.ceil(total / perPage), - currentPage: Number(page), + currentPage: page, }); } catch (error) { // Логируем ошибку и отправляем ответ с кодом 500 diff --git a/src/routes/articles/crud.ts b/src/routes/articles/crud.ts deleted file mode 100644 index ba0481a..0000000 --- a/src/routes/articles/crud.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { Request, Response } from 'express'; -import { prisma } from '../../lib/prisma'; - -export async function getArticle(req: Request, res: Response) { - try { - const article = await prisma.article.findUnique({ - where: { id: req.params.id }, - include: { - author: { - select: { - id: true, - displayName: true, - email: true - } - } - } - }); - - if (!article) { - return res.status(404).json({ error: 'Article not found' }); - } - - res.json(article); - } catch { - res.status(500).json({ error: 'Server error' }); - } -} - -export async function createArticle(req: Request, res: Response) { - try { - const { title, excerpt, content, category, city, coverImage, readTime } = req.body; - - const article = await prisma.article.create({ - data: { - title, - excerpt, - content, - category, - city, - coverImage, - readTime, - authorId: req.user!.id - }, - include: { - author: { - select: { - id: true, - displayName: true, - email: true - } - } - } - }); - - res.status(201).json(article); - } catch { - res.status(500).json({ error: 'Server error' }); - } -} - -export async function updateArticle(req: Request, res: Response) { - try { - const article = await prisma.article.update({ - where: { id: req.params.id }, - data: req.body, - include: { - author: { - select: { - id: true, - displayName: true, - email: true - } - } - } - }); - - res.json(article); - } catch { - res.status(500).json({ error: 'Server error' }); - } -} - -export async function deleteArticle(req: Request, res: Response) { - try { - await prisma.article.delete({ - where: { id: req.params.id } - }); - - res.json({ message: 'Article deleted successfully' }); - } catch { - res.status(500).json({ error: 'Server error' }); - } -} \ No newline at end of file diff --git a/src/routes/articles/index.ts b/src/routes/articles/index.ts index 71ccda1..d66e758 100644 --- a/src/routes/articles/index.ts +++ b/src/routes/articles/index.ts @@ -2,14 +2,19 @@ import express from 'express'; import { auth } from '../../middleware/auth'; import { searchArticles } from './controllers/search'; import { listArticles } from './controllers/list'; -import { getArticle, createArticle, updateArticle, deleteArticle } from './controllers/crud'; +import { getArticle, createArticle, updateArticle, deleteArticle, importArticles } from './controllers/crud'; const router = express.Router(); -// Search and list routes +// Поиск и список routes router.get('/search', searchArticles); router.get('/', listArticles); +// Импорт route +// Настройка middleware для обработки JSON +router.use(express.json({ limit: '10mb' })); +router.post('/import', auth, importArticles); + // CRUD routes router.get('/:id', getArticle); router.post('/', auth, createArticle); diff --git a/src/routes/articles/list.ts b/src/routes/articles/list.ts deleted file mode 100644 index 3cc4121..0000000 --- a/src/routes/articles/list.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Request, Response } from 'express'; -import { prisma } from '../../lib/prisma'; - -export async function listArticles(req: Request, res: Response) { - try { - const { page = 1, category, city } = req.query; - const perPage = 6; - - const where = { - ...(category && { category: category as string }), - ...(city && { city: city as string }) - }; - - const [articles, total] = await Promise.all([ - prisma.article.findMany({ - where, - include: { - author: { - select: { - id: true, - displayName: true, - email: true - } - } - }, - skip: ((page as number) - 1) * perPage, - take: perPage, - orderBy: { publishedAt: 'desc' } - }), - prisma.article.count({ where }) - ]); - - res.json({ - articles, - totalPages: Math.ceil(total / perPage), - currentPage: parseInt(page as string) - }); - } catch { - res.status(500).json({ error: 'Server error' }); - } -} \ No newline at end of file diff --git a/src/routes/articles/search.ts b/src/routes/articles/search.ts deleted file mode 100644 index 86a5d6a..0000000 --- a/src/routes/articles/search.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Request, Response } from 'express'; -import { prisma } from '../../lib/prisma'; - -export async function searchArticles(req: Request, res: Response) { - try { - const { q, page = 1, limit = 9 } = req.query; - const skip = ((page as number) - 1) * (limit as number); - - const where = { - OR: [ - { title: { contains: q as string, mode: 'insensitive' } }, - { excerpt: { contains: q as string, mode: 'insensitive' } }, - { content: { contains: q as string, mode: 'insensitive' } }, - ] - }; - - const [articles, total] = await Promise.all([ - prisma.article.findMany({ - where, - include: { - author: { - select: { - id: true, - displayName: true, - email: true - } - } - }, - skip, - take: parseInt(limit as string), - orderBy: { publishedAt: 'desc' } - }), - prisma.article.count({ where }) - ]); - - res.json({ - articles, - totalPages: Math.ceil(total / (limit as number)), - currentPage: parseInt(page as string) - }); - } catch { - res.status(500).json({ error: 'Server error' }); - } -} \ No newline at end of file diff --git a/src/routes/images/index.ts b/src/routes/images/index.ts index 70fbea3..c37f79f 100644 --- a/src/routes/images/index.ts +++ b/src/routes/images/index.ts @@ -1,6 +1,6 @@ import express from 'express'; import { auth } from '../../middleware/auth'; -import {createS3Client, getMulterS3Config, uploadToS3} from '../../services/s3Service'; +import { createS3Client, getMulterS3Config, uploadToS3 } from '../../services/s3Service'; import { logger } from '../../config/logger'; const router = express.Router();