284 lines
7.6 KiB
JavaScript
284 lines
7.6 KiB
JavaScript
const express = require('express');
|
|
const router = express.Router();
|
|
const multer = require('multer');
|
|
const path = require('path');
|
|
const { Portfolio, Service, Contact, User } = require('../../models');
|
|
|
|
// Multer configuration for file uploads
|
|
const storage = multer.diskStorage({
|
|
destination: (req, file, cb) => {
|
|
cb(null, 'public/uploads/');
|
|
},
|
|
filename: (req, file, cb) => {
|
|
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
|
|
cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname));
|
|
}
|
|
});
|
|
|
|
const upload = multer({
|
|
storage: storage,
|
|
fileFilter: (req, file, cb) => {
|
|
if (file.mimetype.startsWith('image/')) {
|
|
cb(null, true);
|
|
} else {
|
|
cb(new Error('Only image files are allowed!'), false);
|
|
}
|
|
},
|
|
limits: {
|
|
fileSize: 10 * 1024 * 1024 // 10MB
|
|
}
|
|
});
|
|
|
|
// Authentication middleware
|
|
const requireAuth = (req, res, next) => {
|
|
if (!req.session.user) {
|
|
return res.status(401).json({ success: false, message: 'Authentication required' });
|
|
}
|
|
next();
|
|
};
|
|
|
|
// Portfolio API Routes
|
|
router.post('/portfolio', requireAuth, upload.array('images', 10), async (req, res) => {
|
|
try {
|
|
const {
|
|
title,
|
|
shortDescription,
|
|
description,
|
|
category,
|
|
clientName,
|
|
projectUrl,
|
|
githubUrl,
|
|
technologies,
|
|
featured,
|
|
isPublished
|
|
} = req.body;
|
|
|
|
// Process uploaded images
|
|
const images = req.files ? req.files.map((file, index) => ({
|
|
url: `/uploads/${file.filename}`,
|
|
alt: `${title} image ${index + 1}`,
|
|
isPrimary: index === 0
|
|
})) : [];
|
|
|
|
// Parse technologies
|
|
let techArray = [];
|
|
if (technologies) {
|
|
try {
|
|
techArray = JSON.parse(technologies);
|
|
} catch (e) {
|
|
techArray = technologies.split(',').map(t => t.trim());
|
|
}
|
|
}
|
|
|
|
const portfolio = await Portfolio.create({
|
|
title,
|
|
shortDescription,
|
|
description,
|
|
category,
|
|
clientName,
|
|
projectUrl: projectUrl || null,
|
|
githubUrl: githubUrl || null,
|
|
technologies: techArray,
|
|
images,
|
|
featured: featured === 'on',
|
|
isPublished: isPublished === 'on',
|
|
status: 'completed',
|
|
publishedAt: isPublished === 'on' ? new Date() : null
|
|
});
|
|
|
|
res.json({ success: true, portfolio });
|
|
} catch (error) {
|
|
console.error('Portfolio creation error:', error);
|
|
res.status(500).json({ success: false, message: error.message });
|
|
}
|
|
});
|
|
|
|
router.patch('/portfolio/:id', requireAuth, upload.array('images', 10), async (req, res) => {
|
|
try {
|
|
const portfolio = await Portfolio.findByPk(req.params.id);
|
|
if (!portfolio) {
|
|
return res.status(404).json({ success: false, message: 'Portfolio not found' });
|
|
}
|
|
|
|
const updates = { ...req.body };
|
|
|
|
// Handle checkboxes
|
|
updates.featured = updates.featured === 'on';
|
|
updates.isPublished = updates.isPublished === 'on';
|
|
|
|
// Process technologies
|
|
if (updates.technologies) {
|
|
try {
|
|
updates.technologies = JSON.parse(updates.technologies);
|
|
} catch (e) {
|
|
updates.technologies = updates.technologies.split(',').map(t => t.trim());
|
|
}
|
|
}
|
|
|
|
// Process new images
|
|
if (req.files && req.files.length > 0) {
|
|
const newImages = req.files.map((file, index) => ({
|
|
url: `/uploads/${file.filename}`,
|
|
alt: `${updates.title || portfolio.title} image ${index + 1}`,
|
|
isPrimary: index === 0 && (!portfolio.images || portfolio.images.length === 0)
|
|
}));
|
|
|
|
updates.images = [...(portfolio.images || []), ...newImages];
|
|
}
|
|
|
|
await portfolio.update(updates);
|
|
res.json({ success: true, portfolio });
|
|
} catch (error) {
|
|
console.error('Portfolio update error:', error);
|
|
res.status(500).json({ success: false, message: error.message });
|
|
}
|
|
});
|
|
|
|
router.delete('/portfolio/:id', requireAuth, async (req, res) => {
|
|
try {
|
|
const portfolio = await Portfolio.findByPk(req.params.id);
|
|
if (!portfolio) {
|
|
return res.status(404).json({ success: false, message: 'Portfolio not found' });
|
|
}
|
|
|
|
await portfolio.destroy();
|
|
res.json({ success: true });
|
|
} catch (error) {
|
|
console.error('Portfolio deletion error:', error);
|
|
res.status(500).json({ success: false, message: error.message });
|
|
}
|
|
});
|
|
|
|
// Services API Routes
|
|
router.post('/services', requireAuth, async (req, res) => {
|
|
try {
|
|
const {
|
|
name,
|
|
description,
|
|
shortDescription,
|
|
icon,
|
|
category,
|
|
features,
|
|
pricing,
|
|
estimatedTime,
|
|
isActive,
|
|
featured,
|
|
tags
|
|
} = req.body;
|
|
|
|
// Parse arrays
|
|
let featuresArray = [];
|
|
let tagsArray = [];
|
|
let pricingObj = {};
|
|
|
|
if (features) {
|
|
try {
|
|
featuresArray = JSON.parse(features);
|
|
} catch (e) {
|
|
featuresArray = features.split(',').map(f => f.trim());
|
|
}
|
|
}
|
|
|
|
if (tags) {
|
|
try {
|
|
tagsArray = JSON.parse(tags);
|
|
} catch (e) {
|
|
tagsArray = tags.split(',').map(t => t.trim());
|
|
}
|
|
}
|
|
|
|
if (pricing) {
|
|
try {
|
|
pricingObj = JSON.parse(pricing);
|
|
} catch (e) {
|
|
pricingObj = { basePrice: pricing };
|
|
}
|
|
}
|
|
|
|
const service = await Service.create({
|
|
name,
|
|
description,
|
|
shortDescription,
|
|
icon,
|
|
category,
|
|
features: featuresArray,
|
|
pricing: pricingObj,
|
|
estimatedTime,
|
|
isActive: isActive === 'on',
|
|
featured: featured === 'on',
|
|
tags: tagsArray
|
|
});
|
|
|
|
res.json({ success: true, service });
|
|
} catch (error) {
|
|
console.error('Service creation error:', error);
|
|
res.status(500).json({ success: false, message: error.message });
|
|
}
|
|
});
|
|
|
|
router.delete('/services/:id', requireAuth, async (req, res) => {
|
|
try {
|
|
const service = await Service.findByPk(req.params.id);
|
|
if (!service) {
|
|
return res.status(404).json({ success: false, message: 'Service not found' });
|
|
}
|
|
|
|
await service.destroy();
|
|
res.json({ success: true });
|
|
} catch (error) {
|
|
console.error('Service deletion error:', error);
|
|
res.status(500).json({ success: false, message: error.message });
|
|
}
|
|
});
|
|
|
|
// Contacts API Routes
|
|
router.patch('/contacts/:id', requireAuth, async (req, res) => {
|
|
try {
|
|
const contact = await Contact.findByPk(req.params.id);
|
|
if (!contact) {
|
|
return res.status(404).json({ success: false, message: 'Contact not found' });
|
|
}
|
|
|
|
await contact.update(req.body);
|
|
res.json({ success: true, contact });
|
|
} catch (error) {
|
|
console.error('Contact update error:', error);
|
|
res.status(500).json({ success: false, message: error.message });
|
|
}
|
|
});
|
|
|
|
router.delete('/contacts/:id', requireAuth, async (req, res) => {
|
|
try {
|
|
const contact = await Contact.findByPk(req.params.id);
|
|
if (!contact) {
|
|
return res.status(404).json({ success: false, message: 'Contact not found' });
|
|
}
|
|
|
|
await contact.destroy();
|
|
res.json({ success: true });
|
|
} catch (error) {
|
|
console.error('Contact deletion error:', error);
|
|
res.status(500).json({ success: false, message: error.message });
|
|
}
|
|
});
|
|
|
|
// Telegram notification for contact
|
|
router.post('/contacts/:id/telegram', requireAuth, async (req, res) => {
|
|
try {
|
|
const contact = await Contact.findByPk(req.params.id);
|
|
if (!contact) {
|
|
return res.status(404).json({ success: false, message: 'Contact not found' });
|
|
}
|
|
|
|
// Send Telegram notification (we'll implement this with Telegram bot)
|
|
const telegramService = require('../../services/telegram');
|
|
await telegramService.sendContactNotification(contact);
|
|
|
|
res.json({ success: true });
|
|
} catch (error) {
|
|
console.error('Telegram notification error:', error);
|
|
res.status(500).json({ success: false, message: error.message });
|
|
}
|
|
});
|
|
|
|
module.exports = router; |