escambalkon's picture
sunucuya veritabanı kur
7bfe715 verified
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const multer = require('multer');
const path = require('path');
const fs = require('fs');
require('dotenv').config();
const app = express();
const PORT = process.env.PORT || 3001;
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key-here';
// Middleware
app.use(cors());
app.use(express.json({ limit: '50mb' }));
app.use(express.urlencoded({ extended: true, limit: '50mb' }));
// Serve static files
app.use('/uploads', express.static(path.join(__dirname, 'uploads')));
// Ensure uploads directory exists
const uploadsDir = path.join(__dirname, 'uploads');
if (!fs.existsSync(uploadsDir)) {
fs.mkdirSync(uploadsDir, { recursive: true });
}
// Multer configuration for file uploads
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads/');
},
filename: (req, file, cb) => {
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
cb(null, uniqueSuffix + path.extname(file.originalname));
}
});
const upload = multer({
storage: storage,
limits: { fileSize: 10 * 1024 * 1024 }, // 10MB limit
fileFilter: (req, file, cb) => {
if (file.mimetype.startsWith('image/')) {
cb(null, true);
} else {
cb(new Error('Only image files are allowed'));
}
}
});
// MongoDB Connection
mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost:27017/pencere-hesaplama', {
useNewUrlParser: true,
useUnifiedTopology: true,
}).then(() => {
console.log('Connected to MongoDB');
}).catch(err => {
console.error('MongoDB connection error:', err);
});
// Schemas
const userSchema = new mongoose.Schema({
username: { type: String, required: true, unique: true },
password: { type: String, required: true },
email: { type: String, required: true, unique: true },
role: { type: String, enum: ['admin', 'user'], default: 'user' },
createdAt: { type: Date, default: Date.now }
});
const companySchema = new mongoose.Schema({
name: { type: String, required: true },
logo: { type: String },
address: { type: String },
phone: { type: String },
email: { type: String },
website: { type: String },
description: { type: String },
createdAt: { type: Date, default: Date.now }
});
const systemSchema = new mongoose.Schema({
name: { type: String, required: true },
image: { type: String },
parts: [{
name: { type: String, required: true },
type: { type: String, enum: ['yatay', 'dikey', 'cam'], required: true },
quantity: { type: Number, required: true, default: 1 },
reduction: { type: Number, default: 0 },
description: { type: String },
image: { type: String },
advancedFormula: {
formula: { type: String },
type: { type: String }
},
glassFormulas: {
horizontal: { type: String },
horizontalType: { type: String },
vertical: { type: String },
verticalType: { type: String }
},
createdAt: { type: Date, default: Date.now }
}],
createdAt: { type: Date, default: Date.now },
updatedAt: { type: Date, default: Date.now }
});
const customerSchema = new mongoose.Schema({
name: { type: String, required: true, unique: true },
phone: { type: String },
email: { type: String },
address: { type: String },
createdAt: { type: Date, default: Date.now },
updatedAt: { type: Date, default: Date.now }
});
const positionSchema = new mongoose.Schema({
customerId: { type: mongoose.Schema.Types.ObjectId, ref: 'Customer', required: false },
projectId: { type: mongoose.Schema.Types.ObjectId, ref: 'Project' },
systemId: { type: mongoose.Schema.Types.ObjectId, ref: 'System', required: true },
projectName: { type: String },
width: { type: Number, required: true },
height: { type: Number, required: true },
quantity: { type: Number, required: true, default: 1 },
customerName: { type: String },
horizontalParts: [{
name: { type: String },
size: { type: Number },
quantity: { type: Number },
formulaUsed: { type: Boolean }
}],
verticalParts: [{
name: { type: String },
size: { type: Number },
quantity: { type: Number },
formulaUsed: { type: Boolean }
}],
glassParts: [{
name: { type: String },
quantity: { type: Number },
size: { type: String },
width: { type: Number },
height: { type: Number },
totalArea: { type: String }
}],
glassInfo: {
width: { type: Number },
height: { type: Number },
totalArea: { type: String }
},
pozNumber: { type: Number },
createdAt: { type: Date, default: Date.now },
updatedAt: { type: Date, default: Date.now }
});
const projectSchema = new mongoose.Schema({
name: { type: String, required: true },
customerId: { type: mongoose.Schema.Types.ObjectId, ref: 'Customer' },
description: { type: String },
startDate: { type: Date },
endDate: { type: Date },
status: { type: String, enum: ['active', 'completed', 'cancelled'], default: 'active' },
createdAt: { type: Date, default: Date.now },
updatedAt: { type: Date, default: Date.now }
});
const pdfSettingsSchema = new mongoose.Schema({
settings: { type: Object, required: true },
type: { type: String, enum: ['global', 'perpage'], required: true },
isActive: { type: Boolean, default: true },
createdAt: { type: Date, default: Date.now },
updatedAt: { type: Date, default: Date.now }
});
// Models
const User = mongoose.model('User', userSchema);
const Company = mongoose.model('Company', companySchema);
const System = mongoose.model('System', systemSchema);
const Customer = mongoose.model('Customer', customerSchema);
const Position = mongoose.model('Position', positionSchema);
const Project = mongoose.model('Project', projectSchema);
const PDFSettings = mongoose.model('PDFSettings', pdfSettingsSchema);
// Authentication Middleware
const authenticateToken = (req, res, next) => {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'Access token required' });
}
jwt.verify(token, JWT_SECRET, (err, user) => {
if (err) {
return res.status(403).json({ error: 'Invalid token' });
}
req.user = user;
next();
});
};
// Helper Functions
const generatePozNumber = async (customerId = null) => {
const query = customerId ? { customerId } : { customerId: null };
const lastPosition = await Position.findOne(query).sort({ pozNumber: -1 });
return lastPosition ? lastPosition.pozNumber + 1 : 1;
};
// Auth Routes
app.post('/api/auth/register', async (req, res) => {
try {
const { username, email, password } = req.body;
if (!username || !email || !password) {
return res.status(400).json({ error: 'All fields are required' });
}
const existingUser = await User.findOne({
$or: [{ username }, { email }]
});
if (existingUser) {
return res.status(400).json({ error: 'Username or email already exists' });
}
const hashedPassword = await bcrypt.hash(password, 10);
const user = new User({ username, email, password: hashedPassword });
await user.save();
const token = jwt.sign(
{ userId: user._id, username: user.username, role: user.role },
JWT_SECRET,
{ expiresIn: '24h' }
);
res.status(201).json({
message: 'User created successfully',
token,
user: { id: user._id, username: user.username, email: user.email, role: user.role }
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.post('/api/auth/login', async (req, res) => {
try {
const { username, password } = req.body;
if (!username || !password) {
return res.status(400).json({ error: 'Username and password are required' });
}
const user = await User.findOne({ username });
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' });
}
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res.status(401).json({ error: 'Invalid credentials' });
}
const token = jwt.sign(
{ userId: user._id, username: user.username, role: user.role },
JWT_SECRET,
{ expiresIn: '24h' }
);
res.json({
message: 'Login successful',
token,
user: { id: user._id, username: user.username, email: user.email, role: user.role }
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Company Routes
app.get('/api/company', async (req, res) => {
try {
let company = await Company.findOne();
if (!company) {
company = new Company({
name: 'Firma Adı',
createdAt: new Date()
});
await company.save();
}
res.json(company);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.put('/api/company', upload.single('logo'), async (req, res) => {
try {
const updateData = { ...req.body };
if (req.file) {
updateData.logo = `/uploads/${req.file.filename}`;
}
const company = await Company.findOneAndUpdate(
{},
{ $set: updateData, updatedAt: new Date() },
{ new: true, upsert: true }
);
res.json(company);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// System Routes
app.get('/api/systems', async (req, res) => {
try {
const systems = await System.find().sort({ createdAt: -1 });
res.json(systems);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.post('/api/systems', upload.single('image'), async (req, res) => {
try {
const systemData = { ...req.body };
if (req.file) {
systemData.image = `/uploads/${req.file.filename}`;
}
const system = new System(systemData);
await system.save();
res.status(201).json(system);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.put('/api/systems/:id', upload.single('image'), async (req, res) => {
try {
const updateData = { ...req.body, updatedAt: new Date() };
if (req.file) {
updateData.image = `/uploads/${req.file.filename}`;
}
const system = await System.findByIdAndUpdate(
req.params.id,
updateData,
{ new: true }
);
if (!system) {
return res.status(404).json({ error: 'System not found' });
}
res.json(system);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.delete('/api/systems/:id', async (req, res) => {
try {
const system = await System.findByIdAndDelete(req.params.id);
if (!system) {
return res.status(404).json({ error: 'System not found' });
}
// Delete associated image file
if (system.image && fs.existsSync(path.join(__dirname, system.image))) {
fs.unlinkSync(path.join(__dirname, system.image));
}
res.json({ message: 'System deleted successfully' });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Customer Routes
app.get('/api/customers', async (req, res) => {
try {
const customers = await Customer.find().sort({ name: 1 });
res.json(customers);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.post('/api/customers', async (req, res) => {
try {
const customer = new Customer(req.body);
await customer.save();
res.status(201).json(customer);
} catch (error) {
if (error.code === 11000) {
res.status(400).json({ error: 'Customer name already exists' });
} else {
res.status(500).json({ error: error.message });
}
}
});
app.put('/api/customers/:id', async (req, res) => {
try {
const customer = await Customer.findByIdAndUpdate(
req.params.id,
{ $set: req.body, updatedAt: new Date() },
{ new: true }
);
if (!customer) {
return res.status(404).json({ error: 'Customer not found' });
}
res.json(customer);
} catch (error) {
if (error.code === 11000) {
res.status(400).json({ error: 'Customer name already exists' });
} else {
res.status(500).json({ error: error.message });
}
}
});
app.delete('/api/customers/:id', async (req, res) => {
try {
const customer = await Customer.findByIdAndDelete(req.params.id);
if (!customer) {
return res.status(404).json({ error: 'Customer not found' });
}
// Delete associated positions
await Position.deleteMany({ customerId: req.params.id });
res.json({ message: 'Customer deleted successfully' });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Position Routes
app.get('/api/positions', async (req, res) => {
try {
const { customerId } = req.query;
const query = customerId ? { customerId } : { customerId: null };
const positions = await Position.find(query)
.populate('systemId', 'name image parts')
.sort({ createdAt: -1 });
res.json(positions);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.post('/api/positions', async (req, res) => {
try {
const positionData = { ...req.body };
if (!positionData.pozNumber) {
positionData.pozNumber = await generatePozNumber(positionData.customerId);
}
const position = new Position(positionData);
await position.save();
await position.populate('systemId', 'name image parts');
res.status(201).json(position);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.put('/api/positions/:id', async (req, res) => {
try {
const position = await Position.findByIdAndUpdate(
req.params.id,
{ $set: req.body, updatedAt: new Date() },
{ new: true }
).populate('systemId', 'name image parts');
if (!position) {
return res.status(404).json({ error: 'Position not found' });
}
res.json(position);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.delete('/api/positions/:id', async (req, res) => {
try {
const position = await Position.findByIdAndDelete(req.params.id);
if (!position) {
return res.status(404).json({ error: 'Position not found' });
}
res.json({ message: 'Position deleted successfully' });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// PDF Settings Routes
app.get('/api/pdf-settings', async (req, res) => {
try {
const { type } = req.query;
const query = type ? { type, isActive: true } : { isActive: true };
const settings = await PDFSettings.findOne(query).sort({ createdAt: -1 });
res.json(settings || { settings: {} });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.put('/api/pdf-settings', async (req, res) => {
try {
const { type = 'global', settings } = req.body;
// Deactivate other settings of the same type
await PDFSettings.updateMany({ type }, { isActive: false });
const pdfSettings = new PDFSettings({ type, settings, isActive: true });
await pdfSettings.save();
res.status(201).json(pdfSettings);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Backup Routes
app.get('/api/backup', async (req, res) => {
try {
const backup = {
timestamp: new Date().toISOString(),
systems: await System.find(),
customers: await Customer.find(),
positions: await Position.find(),
company: await Company.findOne(),
pdfSettings: await PDFSettings.find(),
projects: await Project.find()
};
res.setHeader('Content-Type', 'application/json');
res.setHeader('Content-Disposition', `attachment; filename="backup-${new Date().toISOString().split('T')[0]}.json"`);
res.json(backup);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.post('/api/restore', async (req, res) => {
try {
const backup = req.body;
// Clear existing data
await Promise.all([
System.deleteMany({}),
Customer.deleteMany({}),
Position.deleteMany({}),
Company.deleteMany({}),
PDFSettings.deleteMany({}),
Project.deleteMany({})
]);
// Restore data
if (backup.systems && backup.systems.length > 0) {
await System.insertMany(backup.systems);
}
if (backup.customers && backup.customers.length > 0) {
await Customer.insertMany(backup.customers);
}
if (backup.positions && backup.positions.length > 0) {
await Position.insertMany(backup.positions);
}
if (backup.company) {
await Company.create(backup.company);
}
if (backup.pdfSettings && backup.pdfSettings.length > 0) {
await PDFSettings.insertMany(backup.pdfSettings);
}
if (backup.projects && backup.projects.length > 0) {
await Project.insertMany(backup.projects);
}
res.json({ message: 'Data restored successfully' });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Error handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Something went wrong!' });
});
// Start server
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
console.log(`API documentation: http://localhost:${PORT}/api`);
});