396 lines
10 KiB
JavaScript
396 lines
10 KiB
JavaScript
const express = require('express');
|
|
const { Op } = require('sequelize');
|
|
const { ItemRequest, ItemRequestResponse, User, Item } = require('../models');
|
|
const { authenticateToken } = require('../middleware/auth');
|
|
const logger = require('../utils/logger');
|
|
const router = express.Router();
|
|
|
|
router.get('/', async (req, res) => {
|
|
try {
|
|
const {
|
|
search,
|
|
status = 'open',
|
|
page = 1,
|
|
limit = 20
|
|
} = req.query;
|
|
|
|
const where = { status };
|
|
|
|
if (search) {
|
|
where[Op.or] = [
|
|
{ title: { [Op.iLike]: `%${search}%` } },
|
|
{ description: { [Op.iLike]: `%${search}%` } }
|
|
];
|
|
}
|
|
|
|
const offset = (page - 1) * limit;
|
|
|
|
const { count, rows } = await ItemRequest.findAndCountAll({
|
|
where,
|
|
include: [
|
|
{
|
|
model: User,
|
|
as: 'requester',
|
|
attributes: ['id', 'username', 'firstName', 'lastName']
|
|
}
|
|
],
|
|
limit: parseInt(limit),
|
|
offset: parseInt(offset),
|
|
order: [['createdAt', 'DESC']]
|
|
});
|
|
|
|
const reqLogger = logger.withRequestId(req.id);
|
|
reqLogger.info("Item requests fetched", {
|
|
search,
|
|
status,
|
|
requestsCount: count,
|
|
page: parseInt(page),
|
|
limit: parseInt(limit)
|
|
});
|
|
|
|
res.json({
|
|
requests: rows,
|
|
totalPages: Math.ceil(count / limit),
|
|
currentPage: parseInt(page),
|
|
totalRequests: count
|
|
});
|
|
} catch (error) {
|
|
const reqLogger = logger.withRequestId(req.id);
|
|
reqLogger.error("Item requests fetch failed", {
|
|
error: error.message,
|
|
stack: error.stack,
|
|
query: req.query
|
|
});
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
router.get('/my-requests', authenticateToken, async (req, res) => {
|
|
try {
|
|
const requests = await ItemRequest.findAll({
|
|
where: { requesterId: req.user.id },
|
|
include: [
|
|
{
|
|
model: User,
|
|
as: 'requester',
|
|
attributes: ['id', 'username', 'firstName', 'lastName']
|
|
},
|
|
{
|
|
model: ItemRequestResponse,
|
|
as: 'responses',
|
|
include: [
|
|
{
|
|
model: User,
|
|
as: 'responder',
|
|
attributes: ['id', 'username', 'firstName', 'lastName']
|
|
},
|
|
{
|
|
model: Item,
|
|
as: 'existingItem'
|
|
}
|
|
]
|
|
}
|
|
],
|
|
order: [['createdAt', 'DESC']]
|
|
});
|
|
|
|
const reqLogger = logger.withRequestId(req.id);
|
|
reqLogger.info("User item requests fetched", {
|
|
userId: req.user.id,
|
|
requestsCount: requests.length
|
|
});
|
|
|
|
res.json(requests);
|
|
} catch (error) {
|
|
const reqLogger = logger.withRequestId(req.id);
|
|
reqLogger.error("User item requests fetch failed", {
|
|
error: error.message,
|
|
stack: error.stack,
|
|
userId: req.user.id
|
|
});
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
router.get('/:id', async (req, res) => {
|
|
try {
|
|
const request = await ItemRequest.findByPk(req.params.id, {
|
|
include: [
|
|
{
|
|
model: User,
|
|
as: 'requester',
|
|
attributes: ['id', 'username', 'firstName', 'lastName']
|
|
},
|
|
{
|
|
model: ItemRequestResponse,
|
|
as: 'responses',
|
|
include: [
|
|
{
|
|
model: User,
|
|
as: 'responder',
|
|
attributes: ['id', 'username', 'firstName', 'lastName']
|
|
},
|
|
{
|
|
model: Item,
|
|
as: 'existingItem'
|
|
}
|
|
]
|
|
}
|
|
]
|
|
});
|
|
|
|
if (!request) {
|
|
return res.status(404).json({ error: 'Item request not found' });
|
|
}
|
|
|
|
const reqLogger = logger.withRequestId(req.id);
|
|
reqLogger.info("Item request fetched", {
|
|
requestId: req.params.id,
|
|
requesterId: request.requesterId
|
|
});
|
|
|
|
res.json(request);
|
|
} catch (error) {
|
|
const reqLogger = logger.withRequestId(req.id);
|
|
reqLogger.error("Item request fetch failed", {
|
|
error: error.message,
|
|
stack: error.stack,
|
|
requestId: req.params.id
|
|
});
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
router.post('/', authenticateToken, async (req, res) => {
|
|
try {
|
|
const request = await ItemRequest.create({
|
|
...req.body,
|
|
requesterId: req.user.id
|
|
});
|
|
|
|
const requestWithRequester = await ItemRequest.findByPk(request.id, {
|
|
include: [
|
|
{
|
|
model: User,
|
|
as: 'requester',
|
|
attributes: ['id', 'username', 'firstName', 'lastName']
|
|
}
|
|
]
|
|
});
|
|
|
|
const reqLogger = logger.withRequestId(req.id);
|
|
reqLogger.info("Item request created", {
|
|
requestId: request.id,
|
|
requesterId: req.user.id,
|
|
title: req.body.title
|
|
});
|
|
|
|
res.status(201).json(requestWithRequester);
|
|
} catch (error) {
|
|
const reqLogger = logger.withRequestId(req.id);
|
|
reqLogger.error("Item request creation failed", {
|
|
error: error.message,
|
|
stack: error.stack,
|
|
requesterId: req.user.id,
|
|
requestData: logger.sanitize(req.body)
|
|
});
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
router.put('/:id', authenticateToken, async (req, res) => {
|
|
try {
|
|
const request = await ItemRequest.findByPk(req.params.id);
|
|
|
|
if (!request) {
|
|
return res.status(404).json({ error: 'Item request not found' });
|
|
}
|
|
|
|
if (request.requesterId !== req.user.id) {
|
|
return res.status(403).json({ error: 'Unauthorized' });
|
|
}
|
|
|
|
await request.update(req.body);
|
|
|
|
const updatedRequest = await ItemRequest.findByPk(request.id, {
|
|
include: [
|
|
{
|
|
model: User,
|
|
as: 'requester',
|
|
attributes: ['id', 'username', 'firstName', 'lastName']
|
|
}
|
|
]
|
|
});
|
|
|
|
const reqLogger = logger.withRequestId(req.id);
|
|
reqLogger.info("Item request updated", {
|
|
requestId: req.params.id,
|
|
requesterId: req.user.id
|
|
});
|
|
|
|
res.json(updatedRequest);
|
|
} catch (error) {
|
|
const reqLogger = logger.withRequestId(req.id);
|
|
reqLogger.error("Item request update failed", {
|
|
error: error.message,
|
|
stack: error.stack,
|
|
requestId: req.params.id,
|
|
requesterId: req.user.id
|
|
});
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
router.delete('/:id', authenticateToken, async (req, res) => {
|
|
try {
|
|
const request = await ItemRequest.findByPk(req.params.id);
|
|
|
|
if (!request) {
|
|
return res.status(404).json({ error: 'Item request not found' });
|
|
}
|
|
|
|
if (request.requesterId !== req.user.id) {
|
|
return res.status(403).json({ error: 'Unauthorized' });
|
|
}
|
|
|
|
await request.destroy();
|
|
|
|
const reqLogger = logger.withRequestId(req.id);
|
|
reqLogger.info("Item request deleted", {
|
|
requestId: req.params.id,
|
|
requesterId: req.user.id
|
|
});
|
|
|
|
res.status(204).send();
|
|
} catch (error) {
|
|
const reqLogger = logger.withRequestId(req.id);
|
|
reqLogger.error("Item request deletion failed", {
|
|
error: error.message,
|
|
stack: error.stack,
|
|
requestId: req.params.id,
|
|
requesterId: req.user.id
|
|
});
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
router.post('/:id/responses', authenticateToken, async (req, res) => {
|
|
try {
|
|
const request = await ItemRequest.findByPk(req.params.id);
|
|
|
|
if (!request) {
|
|
return res.status(404).json({ error: 'Item request not found' });
|
|
}
|
|
|
|
if (request.requesterId === req.user.id) {
|
|
return res.status(400).json({ error: 'Cannot respond to your own request' });
|
|
}
|
|
|
|
if (request.status !== 'open') {
|
|
return res.status(400).json({ error: 'Cannot respond to closed request' });
|
|
}
|
|
|
|
const response = await ItemRequestResponse.create({
|
|
...req.body,
|
|
itemRequestId: req.params.id,
|
|
responderId: req.user.id
|
|
});
|
|
|
|
await request.increment('responseCount');
|
|
|
|
const responseWithDetails = await ItemRequestResponse.findByPk(response.id, {
|
|
include: [
|
|
{
|
|
model: User,
|
|
as: 'responder',
|
|
attributes: ['id', 'username', 'firstName', 'lastName']
|
|
},
|
|
{
|
|
model: Item,
|
|
as: 'existingItem'
|
|
}
|
|
]
|
|
});
|
|
|
|
const reqLogger = logger.withRequestId(req.id);
|
|
reqLogger.info("Item request response created", {
|
|
requestId: req.params.id,
|
|
responseId: response.id,
|
|
responderId: req.user.id
|
|
});
|
|
|
|
res.status(201).json(responseWithDetails);
|
|
} catch (error) {
|
|
const reqLogger = logger.withRequestId(req.id);
|
|
reqLogger.error("Item request response creation failed", {
|
|
error: error.message,
|
|
stack: error.stack,
|
|
requestId: req.params.id,
|
|
responderId: req.user.id
|
|
});
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
router.put('/responses/:responseId/status', authenticateToken, async (req, res) => {
|
|
try {
|
|
const { status } = req.body;
|
|
const response = await ItemRequestResponse.findByPk(req.params.responseId, {
|
|
include: [
|
|
{
|
|
model: ItemRequest,
|
|
as: 'itemRequest'
|
|
}
|
|
]
|
|
});
|
|
|
|
if (!response) {
|
|
return res.status(404).json({ error: 'Response not found' });
|
|
}
|
|
|
|
if (response.itemRequest.requesterId !== req.user.id) {
|
|
return res.status(403).json({ error: 'Only the requester can update response status' });
|
|
}
|
|
|
|
await response.update({ status });
|
|
|
|
if (status === 'accepted') {
|
|
await response.itemRequest.update({ status: 'fulfilled' });
|
|
}
|
|
|
|
const updatedResponse = await ItemRequestResponse.findByPk(response.id, {
|
|
include: [
|
|
{
|
|
model: User,
|
|
as: 'responder',
|
|
attributes: ['id', 'username', 'firstName', 'lastName']
|
|
},
|
|
{
|
|
model: Item,
|
|
as: 'existingItem'
|
|
}
|
|
]
|
|
});
|
|
|
|
const reqLogger = logger.withRequestId(req.id);
|
|
reqLogger.info("Item request response status updated", {
|
|
responseId: req.params.responseId,
|
|
newStatus: status,
|
|
requesterId: req.user.id,
|
|
requestFulfilled: status === 'accepted'
|
|
});
|
|
|
|
res.json(updatedResponse);
|
|
} catch (error) {
|
|
const reqLogger = logger.withRequestId(req.id);
|
|
reqLogger.error("Item request response status update failed", {
|
|
error: error.message,
|
|
stack: error.stack,
|
|
responseId: req.params.responseId,
|
|
requesterId: req.user.id
|
|
});
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
});
|
|
|
|
module.exports = router; |