337 lines
10 KiB
JavaScript
337 lines
10 KiB
JavaScript
const express = require('express');
|
|
const router = express.Router();
|
|
const { verifyToken } = require('../middleware/auth');
|
|
const Company = require('../models/Company');
|
|
const Experience = require('../models/Experience');
|
|
const Request = require('../models/Request');
|
|
const Message = require('../models/Message');
|
|
const mongoose = require('../../../utils/mongoose');
|
|
const { Types } = mongoose;
|
|
|
|
// GET /my/info - получить мою компанию (требует авторизации) - ДОЛЖНО быть ПЕРЕД /:id
|
|
router.get('/my/info', verifyToken, async (req, res) => {
|
|
try {
|
|
const userId = req.userId;
|
|
const user = await require('../models/User').findById(userId);
|
|
|
|
if (!user || !user.companyId) {
|
|
return res.status(404).json({ error: 'Company not found' });
|
|
}
|
|
|
|
const company = await Company.findById(user.companyId);
|
|
|
|
if (!company) {
|
|
return res.status(404).json({ error: 'Company not found' });
|
|
}
|
|
|
|
res.json({
|
|
...company.toObject(),
|
|
id: company._id
|
|
});
|
|
} catch (error) {
|
|
console.error('Get my company error:', error);
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
// GET /my/stats - получить статистику компании - ДОЛЖНО быть ПЕРЕД /:id
|
|
router.get('/my/stats', verifyToken, async (req, res) => {
|
|
try {
|
|
const userId = req.userId;
|
|
const User = require('../models/User');
|
|
const user = await User.findById(userId);
|
|
|
|
if (!user) {
|
|
return res.status(404).json({ error: 'User not found' });
|
|
}
|
|
|
|
let companyId = user.companyId;
|
|
|
|
if (!companyId) {
|
|
const fallbackCompany = await Company.create({
|
|
fullName: 'Компания пользователя',
|
|
shortName: 'Компания пользователя',
|
|
verified: false,
|
|
partnerGeography: [],
|
|
});
|
|
|
|
user.companyId = fallbackCompany._id;
|
|
user.updatedAt = new Date();
|
|
await user.save();
|
|
companyId = fallbackCompany._id;
|
|
}
|
|
|
|
let company = await Company.findById(companyId);
|
|
|
|
if (!company) {
|
|
company = await Company.create({
|
|
_id: companyId,
|
|
fullName: 'Компания пользователя',
|
|
verified: false,
|
|
partnerGeography: [],
|
|
});
|
|
}
|
|
|
|
const companyIdString = company._id.toString();
|
|
const companyObjectId = Types.ObjectId.isValid(companyIdString)
|
|
? new Types.ObjectId(companyIdString)
|
|
: null;
|
|
|
|
const [sentRequests, receivedRequests, unreadMessages] = await Promise.all([
|
|
Request.countDocuments({ senderCompanyId: companyIdString }),
|
|
Request.countDocuments({ recipientCompanyId: companyIdString }),
|
|
companyObjectId
|
|
? Message.countDocuments({ recipientCompanyId: companyObjectId, read: false })
|
|
: Promise.resolve(0),
|
|
]);
|
|
|
|
// Подсчитываем просмотры профиля из запросов к профилю компании
|
|
const profileViews = company?.metrics?.profileViews || 0;
|
|
|
|
// Получаем статистику за последнюю неделю для изменений
|
|
const weekAgo = new Date();
|
|
weekAgo.setDate(weekAgo.getDate() - 7);
|
|
|
|
const sentRequestsLastWeek = await Request.countDocuments({
|
|
senderCompanyId: companyIdString,
|
|
createdAt: { $gte: weekAgo }
|
|
});
|
|
|
|
const receivedRequestsLastWeek = await Request.countDocuments({
|
|
recipientCompanyId: companyIdString,
|
|
createdAt: { $gte: weekAgo }
|
|
});
|
|
|
|
const stats = {
|
|
profileViews: profileViews,
|
|
profileViewsChange: 0, // Можно добавить отслеживание просмотров, если нужно
|
|
sentRequests,
|
|
sentRequestsChange: sentRequestsLastWeek,
|
|
receivedRequests,
|
|
receivedRequestsChange: receivedRequestsLastWeek,
|
|
newMessages: unreadMessages,
|
|
rating: Number.isFinite(company?.rating) ? Number(company.rating) : 0,
|
|
};
|
|
|
|
res.json(stats);
|
|
} catch (error) {
|
|
console.error('Get company stats error:', error);
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
// GET /:id/experience - получить опыт компании
|
|
router.get('/:id/experience', verifyToken, async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
|
|
if (!Types.ObjectId.isValid(id)) {
|
|
return res.status(400).json({ error: 'Invalid company ID' });
|
|
}
|
|
|
|
const experience = await Experience.find({ companyId: new Types.ObjectId(id) })
|
|
.sort({ createdAt: -1 });
|
|
|
|
res.json(experience.map(exp => ({
|
|
...exp.toObject(),
|
|
id: exp._id
|
|
})));
|
|
} catch (error) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
// POST /:id/experience - добавить опыт компании
|
|
router.post('/:id/experience', verifyToken, async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const { confirmed, customer, subject, volume, contact, comment } = req.body;
|
|
|
|
if (!Types.ObjectId.isValid(id)) {
|
|
return res.status(400).json({ error: 'Invalid company ID' });
|
|
}
|
|
|
|
const newExp = await Experience.create({
|
|
companyId: new Types.ObjectId(id),
|
|
confirmed: confirmed || false,
|
|
customer: customer || '',
|
|
subject: subject || '',
|
|
volume: volume || '',
|
|
contact: contact || '',
|
|
comment: comment || ''
|
|
});
|
|
|
|
res.status(201).json({
|
|
...newExp.toObject(),
|
|
id: newExp._id
|
|
});
|
|
} catch (error) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
// PUT /:id/experience/:expId - обновить опыт
|
|
router.put('/:id/experience/:expId', verifyToken, async (req, res) => {
|
|
try {
|
|
const { id, expId } = req.params;
|
|
|
|
if (!Types.ObjectId.isValid(id) || !Types.ObjectId.isValid(expId)) {
|
|
return res.status(400).json({ error: 'Invalid IDs' });
|
|
}
|
|
|
|
const experience = await Experience.findByIdAndUpdate(
|
|
new Types.ObjectId(expId),
|
|
{
|
|
...req.body,
|
|
updatedAt: new Date()
|
|
},
|
|
{ new: true }
|
|
);
|
|
|
|
if (!experience || experience.companyId.toString() !== id) {
|
|
return res.status(404).json({ error: 'Experience not found' });
|
|
}
|
|
|
|
res.json({
|
|
...experience.toObject(),
|
|
id: experience._id
|
|
});
|
|
} catch (error) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
// DELETE /:id/experience/:expId - удалить опыт
|
|
router.delete('/:id/experience/:expId', verifyToken, async (req, res) => {
|
|
try {
|
|
const { id, expId } = req.params;
|
|
|
|
if (!Types.ObjectId.isValid(id) || !Types.ObjectId.isValid(expId)) {
|
|
return res.status(400).json({ error: 'Invalid IDs' });
|
|
}
|
|
|
|
const experience = await Experience.findById(new Types.ObjectId(expId));
|
|
|
|
if (!experience || experience.companyId.toString() !== id) {
|
|
return res.status(404).json({ error: 'Experience not found' });
|
|
}
|
|
|
|
await Experience.findByIdAndDelete(new Types.ObjectId(expId));
|
|
res.json({ message: 'Experience deleted' });
|
|
} catch (error) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
// Получить компанию по ID (ДОЛЖНО быть ПОСЛЕ специфичных маршрутов)
|
|
router.get('/:id', async (req, res) => {
|
|
try {
|
|
const company = await Company.findById(req.params.id);
|
|
|
|
if (!company) {
|
|
if (!Types.ObjectId.isValid(req.params.id)) {
|
|
return res.status(404).json({ error: 'Company not found' });
|
|
}
|
|
|
|
const placeholder = await Company.create({
|
|
_id: new Types.ObjectId(req.params.id),
|
|
fullName: 'Новая компания',
|
|
shortName: 'Новая компания',
|
|
verified: false,
|
|
partnerGeography: [],
|
|
industry: '',
|
|
companySize: '',
|
|
});
|
|
|
|
return res.json({
|
|
...placeholder.toObject(),
|
|
id: placeholder._id,
|
|
});
|
|
}
|
|
|
|
// Отслеживаем просмотр профиля (если это не владелец компании)
|
|
const userId = req.userId;
|
|
if (userId) {
|
|
const User = require('../models/User');
|
|
const user = await User.findById(userId);
|
|
if (user && user.companyId && user.companyId.toString() !== company._id.toString()) {
|
|
// Инкрементируем просмотры профиля
|
|
if (!company.metrics) {
|
|
company.metrics = {};
|
|
}
|
|
if (!company.metrics.profileViews) {
|
|
company.metrics.profileViews = 0;
|
|
}
|
|
company.metrics.profileViews = (company.metrics.profileViews || 0) + 1;
|
|
await company.save();
|
|
}
|
|
}
|
|
|
|
res.json({
|
|
...company.toObject(),
|
|
id: company._id
|
|
});
|
|
} catch (error) {
|
|
console.error('Get company error:', error);
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
// Обновить компанию (требует авторизации)
|
|
const updateCompanyHandler = async (req, res) => {
|
|
try {
|
|
const company = await Company.findByIdAndUpdate(
|
|
req.params.id,
|
|
{ ...req.body, updatedAt: new Date() },
|
|
{ new: true }
|
|
);
|
|
|
|
if (!company) {
|
|
return res.status(404).json({ error: 'Company not found' });
|
|
}
|
|
|
|
res.json({
|
|
...company.toObject(),
|
|
id: company._id
|
|
});
|
|
} catch (error) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
};
|
|
|
|
router.put('/:id', verifyToken, updateCompanyHandler);
|
|
router.patch('/:id', verifyToken, updateCompanyHandler);
|
|
|
|
// Поиск с AI анализом
|
|
router.post('/ai-search', async (req, res) => {
|
|
try {
|
|
const { query } = req.body;
|
|
|
|
if (!query) {
|
|
return res.status(400).json({ error: 'Query required' });
|
|
}
|
|
|
|
const q = query.toLowerCase();
|
|
const result = await Company.find({
|
|
$or: [
|
|
{ fullName: { $regex: q, $options: 'i' } },
|
|
{ shortName: { $regex: q, $options: 'i' } },
|
|
{ industry: { $regex: q, $options: 'i' } }
|
|
]
|
|
});
|
|
|
|
res.json({
|
|
companies: result.map(c => ({
|
|
...c.toObject(),
|
|
id: c._id
|
|
})),
|
|
total: result.length,
|
|
aiSuggestion: `Found ${result.length} companies matching "${query}"`
|
|
});
|
|
} catch (error) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
module.exports = router;
|