-
Notifications
You must be signed in to change notification settings - Fork 0
adding new feature #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,239 @@ | ||
const database = require('../config/database'); | ||
|
||
class ActivityController { | ||
// Get all activities | ||
async getAllActivities(req, res) { | ||
try { | ||
const db = database.getConnection(); | ||
const { page = 1, limit = 50, todo_id } = req.query; | ||
const offset = (page - 1) * limit; | ||
|
||
let sql = ` | ||
SELECT | ||
a.*, | ||
t.title as todo_title | ||
FROM activities a | ||
LEFT JOIN todos t ON a.todo_id = t.id | ||
`; | ||
let params = []; | ||
|
||
if (todo_id) { | ||
sql += ' WHERE a.todo_id = ?'; | ||
params.push(todo_id); | ||
} | ||
|
||
sql += ' ORDER BY a.created_at DESC LIMIT ? OFFSET ?'; | ||
params.push(parseInt(limit), parseInt(offset)); | ||
|
||
db.all(sql, params, (err, rows) => { | ||
if (err) { | ||
res.status(500).json({ error: err.message }); | ||
return; | ||
} | ||
|
||
// Get total count for pagination | ||
let countSql = 'SELECT COUNT(*) as total FROM activities'; | ||
let countParams = []; | ||
|
||
if (todo_id) { | ||
countSql += ' WHERE todo_id = ?'; | ||
countParams.push(todo_id); | ||
} | ||
|
||
db.get(countSql, countParams, (err, countResult) => { | ||
if (err) { | ||
res.status(500).json({ error: err.message }); | ||
return; | ||
} | ||
|
||
res.json({ | ||
activities: rows, | ||
pagination: { | ||
page: parseInt(page), | ||
limit: parseInt(limit), | ||
total: countResult.total, | ||
pages: Math.ceil(countResult.total / limit) | ||
} | ||
}); | ||
}); | ||
}); | ||
} catch (error) { | ||
res.status(500).json({ error: 'Internal server error' }); | ||
} | ||
} | ||
|
||
// Get activities for a specific todo | ||
async getActivitiesByTodoId(req, res) { | ||
try { | ||
const { todoId } = req.params; | ||
const db = database.getConnection(); | ||
|
||
const sql = ` | ||
SELECT | ||
a.*, | ||
t.title as todo_title | ||
FROM activities a | ||
LEFT JOIN todos t ON a.todo_id = t.id | ||
WHERE a.todo_id = ? | ||
ORDER BY a.created_at DESC | ||
`; | ||
|
||
db.all(sql, [todoId], (err, rows) => { | ||
if (err) { | ||
res.status(500).json({ error: err.message }); | ||
return; | ||
} | ||
res.json(rows); | ||
}); | ||
} catch (error) { | ||
res.status(500).json({ error: 'Internal server error' }); | ||
} | ||
} | ||
|
||
// Get a single activity by id | ||
async getActivityById(req, res) { | ||
try { | ||
const { id } = req.params; | ||
const db = database.getConnection(); | ||
|
||
const sql = ` | ||
SELECT | ||
a.*, | ||
t.title as todo_title | ||
FROM activities a | ||
LEFT JOIN todos t ON a.todo_id = t.id | ||
WHERE a.id = ? | ||
`; | ||
|
||
db.get(sql, [id], (err, row) => { | ||
if (err) { | ||
res.status(500).json({ error: err.message }); | ||
return; | ||
} | ||
if (!row) { | ||
res.status(404).json({ error: 'Activity not found' }); | ||
return; | ||
} | ||
res.json(row); | ||
}); | ||
} catch (error) { | ||
res.status(500).json({ error: 'Internal server error' }); | ||
} | ||
} | ||
|
||
// Create a new activity (usually called internally) | ||
async createActivity(activityData) { | ||
return new Promise((resolve, reject) => { | ||
const db = database.getConnection(); | ||
const { | ||
todo_id, | ||
action, | ||
description, | ||
old_value, | ||
new_value, | ||
user_ip, | ||
user_agent | ||
} = activityData; | ||
|
||
const sql = ` | ||
INSERT INTO activities ( | ||
todo_id, action, description, old_value, new_value, user_ip, user_agent | ||
) VALUES (?, ?, ?, ?, ?, ?, ?) | ||
`; | ||
|
||
db.run(sql, [ | ||
todo_id, | ||
action, | ||
description, | ||
old_value, | ||
new_value, | ||
user_ip, | ||
user_agent | ||
], function(err) { | ||
if (err) { | ||
reject(err); | ||
} else { | ||
resolve(this.lastID); | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
// Delete an activity | ||
async deleteActivity(req, res) { | ||
try { | ||
const { id } = req.params; | ||
const db = database.getConnection(); | ||
|
||
db.run('DELETE FROM activities WHERE id = ?', [id], function(err) { | ||
if (err) { | ||
res.status(500).json({ error: err.message }); | ||
return; | ||
} | ||
if (this.changes === 0) { | ||
res.status(404).json({ error: 'Activity not found' }); | ||
return; | ||
} | ||
res.json({ message: 'Activity deleted successfully' }); | ||
}); | ||
} catch (error) { | ||
res.status(500).json({ error: 'Internal server error' }); | ||
} | ||
} | ||
|
||
// Clear all activities (admin function) | ||
async clearAllActivities(req, res) { | ||
try { | ||
const db = database.getConnection(); | ||
|
||
db.run('DELETE FROM activities', function(err) { | ||
if (err) { | ||
res.status(500).json({ error: err.message }); | ||
return; | ||
} | ||
res.json({ | ||
message: 'All activities cleared successfully', | ||
deletedCount: this.changes | ||
}); | ||
}); | ||
} catch (error) { | ||
res.status(500).json({ error: 'Internal server error' }); | ||
} | ||
} | ||
Comment on lines
+184
to
+202
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Security concern: clearAllActivities lacks authorization check. The This endpoint should verify admin privileges before execution. Consider adding middleware for authorization: // In your route definition, add authorization middleware:
router.delete('/', requireAdmin, activityController.clearAllActivities); Also consider adding a confirmation mechanism to prevent accidental deletion. 🤖 Prompt for AI Agents
|
||
|
||
// Get activity statistics | ||
async getActivityStats(req, res) { | ||
try { | ||
const db = database.getConnection(); | ||
|
||
const statsQueries = [ | ||
'SELECT COUNT(*) as total FROM activities', | ||
'SELECT COUNT(*) as today FROM activities WHERE DATE(created_at) = DATE("now")', | ||
'SELECT action, COUNT(*) as count FROM activities GROUP BY action', | ||
'SELECT DATE(created_at) as date, COUNT(*) as count FROM activities GROUP BY DATE(created_at) ORDER BY date DESC LIMIT 7' | ||
]; | ||
|
||
Promise.all(statsQueries.map(query => | ||
new Promise((resolve, reject) => { | ||
db.all(query, [], (err, rows) => { | ||
if (err) reject(err); | ||
else resolve(rows); | ||
}); | ||
}) | ||
)).then(([total, today, byAction, byDate]) => { | ||
res.json({ | ||
total: total[0].total, | ||
today: today[0].today, | ||
byAction: byAction, | ||
last7Days: byDate | ||
}); | ||
}).catch(err => { | ||
res.status(500).json({ error: err.message }); | ||
}); | ||
} catch (error) { | ||
res.status(500).json({ error: 'Internal server error' }); | ||
} | ||
} | ||
} | ||
|
||
module.exports = new ActivityController(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add input validation for pagination parameters.
The pagination parameters are parsed directly without validation, which could lead to negative offsets or invalid limits.
Add validation for the pagination parameters:
📝 Committable suggestion
🤖 Prompt for AI Agents