Initial commit
This commit is contained in:
237
routes/charger_sessions.js
Executable file
237
routes/charger_sessions.js
Executable file
@@ -0,0 +1,237 @@
|
||||
// routes/charger_sessions.js
|
||||
const express = require('express');
|
||||
const { param, query, body, validationResult } = require('express-validator');
|
||||
const router = express.Router();
|
||||
const verifyToken = require('../middleware/verifyToken');
|
||||
const db = require('../db');
|
||||
|
||||
router.use(verifyToken);
|
||||
|
||||
function handleValidation(req, res, next) {
|
||||
const errors = validationResult(req);
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(400).json({ success: false, errors: errors.array() });
|
||||
}
|
||||
next();
|
||||
}
|
||||
|
||||
// GET /api/charger_sessions?chargerId=...
|
||||
router.get(
|
||||
'/',
|
||||
[query('chargerId').isUUID().withMessage('chargerId deve ser UUID válido')],
|
||||
handleValidation,
|
||||
async (req, res) => {
|
||||
const { chargerId } = req.query;
|
||||
const userId = req.user.id;
|
||||
|
||||
const charger = await db('chargers')
|
||||
.where({ id: chargerId, user_id: userId })
|
||||
.first();
|
||||
|
||||
if (!charger) {
|
||||
return res
|
||||
.status(403)
|
||||
.json({ success: false, message: 'Acesso não autorizado' });
|
||||
}
|
||||
|
||||
const sessions = await db('charger_sessions')
|
||||
.where({ charger_id: chargerId })
|
||||
.orderBy('started_at', 'desc');
|
||||
|
||||
res.json({ success: true, data: sessions });
|
||||
}
|
||||
);
|
||||
|
||||
// GET /api/charger_sessions/:id
|
||||
router.get(
|
||||
'/:id',
|
||||
[param('id').isUUID().withMessage('ID de sessão inválido')],
|
||||
handleValidation,
|
||||
async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const userId = req.user.id;
|
||||
|
||||
const session = await db('charger_sessions')
|
||||
.join('chargers', 'charger_sessions.charger_id', 'chargers.id')
|
||||
.where({ 'charger_sessions.id': id, 'chargers.user_id': userId })
|
||||
.select('charger_sessions.*')
|
||||
.first();
|
||||
|
||||
if (!session) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ success: false, message: 'Sessão não encontrada' });
|
||||
}
|
||||
|
||||
res.json({ success: true, data: session });
|
||||
}
|
||||
);
|
||||
|
||||
// POST /api/charger_sessions
|
||||
router.post(
|
||||
'/',
|
||||
[body('charger_id').isUUID().withMessage('charger_id deve ser UUID válido')],
|
||||
handleValidation,
|
||||
async (req, res) => {
|
||||
const { charger_id } = req.body;
|
||||
const userId = req.user.id;
|
||||
|
||||
const charger = await db('chargers')
|
||||
.where({ id: charger_id, user_id: userId })
|
||||
.first();
|
||||
|
||||
if (!charger) {
|
||||
return res
|
||||
.status(403)
|
||||
.json({ success: false, message: 'Acesso não autorizado' });
|
||||
}
|
||||
|
||||
const [inserted] = await db('charger_sessions')
|
||||
.insert({ charger_id, started_at: new Date() })
|
||||
.returning('*');
|
||||
|
||||
res.status(201).json({ success: true, data: inserted });
|
||||
}
|
||||
);
|
||||
|
||||
// PUT /api/charger_sessions/:id
|
||||
router.put(
|
||||
'/:id',
|
||||
[
|
||||
param('id').isUUID().withMessage('ID de sessão inválido'),
|
||||
body('ended_at').optional().isISO8601().toDate(),
|
||||
body('kwh').optional().isFloat({ min: 0 }),
|
||||
body('cost').optional().isFloat({ min: 0 }),
|
||||
],
|
||||
handleValidation,
|
||||
async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const { ended_at, kwh, cost } = req.body;
|
||||
const userId = req.user.id;
|
||||
|
||||
const session = await db('charger_sessions')
|
||||
.join('chargers', 'charger_sessions.charger_id', 'chargers.id')
|
||||
.where({ 'charger_sessions.id': id, 'chargers.user_id': userId })
|
||||
.first();
|
||||
|
||||
if (!session) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ success: false, message: 'Sessão não encontrada' });
|
||||
}
|
||||
|
||||
const [updated] = await db('charger_sessions')
|
||||
.where({ id })
|
||||
.update({ ended_at, kwh, cost })
|
||||
.returning('*');
|
||||
|
||||
res.json({ success: true, data: updated });
|
||||
}
|
||||
);
|
||||
|
||||
// DELETE /api/charger_sessions/:id
|
||||
router.delete(
|
||||
'/:id',
|
||||
[param('id').isUUID().withMessage('ID de sessão inválido')],
|
||||
handleValidation,
|
||||
async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const userId = req.user.id;
|
||||
|
||||
const deleted = await db('charger_sessions')
|
||||
.join('chargers', 'charger_sessions.charger_id', 'chargers.id')
|
||||
.where({ 'charger_sessions.id': id, 'chargers.user_id': userId })
|
||||
.del();
|
||||
|
||||
if (!deleted) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ success: false, message: 'Sessão não encontrada' });
|
||||
}
|
||||
|
||||
res.json({ success: true, message: 'Sessão excluída com sucesso' });
|
||||
}
|
||||
);
|
||||
|
||||
// GET /api/charger_sessions/history/:chargerId
|
||||
router.get(
|
||||
'/history/:chargerId',
|
||||
[
|
||||
param('chargerId').isUUID().withMessage('chargerId deve ser UUID válido'),
|
||||
query('viewMode')
|
||||
.isIn(['Day', 'Week', 'Month'])
|
||||
.withMessage('viewMode inválido'),
|
||||
],
|
||||
handleValidation,
|
||||
async (req, res) => {
|
||||
const { chargerId } = req.params;
|
||||
const { viewMode } = req.query;
|
||||
const userId = req.user.id;
|
||||
|
||||
// ownership check
|
||||
const charger = await db('chargers')
|
||||
.where({ id: chargerId, user_id: userId })
|
||||
.first();
|
||||
|
||||
if (!charger) {
|
||||
return res
|
||||
.status(403)
|
||||
.json({ success: false, message: 'Acesso não autorizado' });
|
||||
}
|
||||
|
||||
let qb = db('charger_sessions')
|
||||
.where({ charger_id: chargerId })
|
||||
.sum('kwh as total_kwh');
|
||||
|
||||
switch (viewMode) {
|
||||
case 'Day':
|
||||
qb = qb
|
||||
.select(db.raw('DATE(started_at) AS period'))
|
||||
.groupBy(db.raw('DATE(started_at)'))
|
||||
.orderBy('period', 'desc');
|
||||
break;
|
||||
|
||||
case 'Week':
|
||||
qb = qb
|
||||
.select(
|
||||
db.raw('EXTRACT(ISOYEAR FROM started_at) AS y'),
|
||||
db.raw('EXTRACT(WEEK FROM started_at) AS w'),
|
||||
db.raw(
|
||||
"EXTRACT(ISOYEAR FROM started_at)||'-'||LPAD(EXTRACT(WEEK FROM started_at)::text,2,'0') AS period"
|
||||
)
|
||||
)
|
||||
.groupBy('y', 'w')
|
||||
.orderBy([{ column: 'y', order: 'desc' }, { column: 'w', order: 'desc' }]);
|
||||
break;
|
||||
|
||||
case 'Month':
|
||||
qb = qb
|
||||
.select(
|
||||
db.raw('EXTRACT(YEAR FROM started_at) AS y'),
|
||||
db.raw('EXTRACT(MONTH FROM started_at) AS m'),
|
||||
db.raw(
|
||||
"EXTRACT(YEAR FROM started_at)||'-'||LPAD(EXTRACT(MONTH FROM started_at)::text,2,'0') AS period"
|
||||
)
|
||||
)
|
||||
.groupBy('y', 'm')
|
||||
.orderBy([{ column: 'y', order: 'desc' }, { column: 'm', order: 'desc' }]);
|
||||
break;
|
||||
}
|
||||
|
||||
const rows = await qb;
|
||||
|
||||
// ✅ devolve lista vazia em vez de 404
|
||||
if (!rows.length) {
|
||||
return res.json({ success: true, data: [] });
|
||||
}
|
||||
|
||||
const data = rows.map((r) => ({
|
||||
started_at: r.period,
|
||||
kwh: parseFloat(r.total_kwh) || 0,
|
||||
}));
|
||||
|
||||
res.json({ success: true, data });
|
||||
}
|
||||
);
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user