fix(scheduler): implement deadline-based matching with 5-run limit and fix security issues
Security fixes: - Replace $queryRawUnsafe with parameterized $queryRaw in admin.js to prevent SQL injection - Use PostgreSQL ANY() operator for safe array parameter handling Scheduler improvements: - Add registrationDeadline support - scheduler now waits until deadline before running - Implement 5-run limit after deadline (runs exactly 5 times with 5-minute intervals) - Add countScheduledRunsAfterDeadline() to track post-deadline runs - Add environment variable validation with sensible min/max ranges - Fix Prisma query syntax (remove invalid endDate null check for non-nullable field) UI improvements: - Fix colspan mismatch in MatchingRunsSection (6 → 8 columns) - Remove duplicate "Uruchom Matching" button, keep only "Run now" with audit tracking - Simplify MatchingConfigSection to focus on deadline configuration Logging enhancements: - Add detailed scheduler logs showing run progress (e.g., "Running post-deadline matching (3/5)") - Log wait times before deadline and between runs - Show completion status after 5 runs
This commit is contained in:
@@ -108,17 +108,16 @@ router.get('/events/:slug/matching-runs', authenticate, async (req, res, next) =
|
||||
// Cheap and valuable: shows actual created pairs in this run.
|
||||
if (runs.length > 0) {
|
||||
const runIds = runs.map(r => r.id);
|
||||
// Single SQL query for all listed runs
|
||||
const placeholders = runIds.join(',');
|
||||
const aggRows = await prisma.$queryRawUnsafe(
|
||||
`SELECT origin_run_id AS "originRunId",
|
||||
COUNT(*)::int AS "totalSuggestions",
|
||||
COUNT(*) FILTER (WHERE recorder_id IS NOT NULL)::int AS "assignedCount",
|
||||
COUNT(*) FILTER (WHERE status = 'not_found')::int AS "notFoundCount"
|
||||
FROM recording_suggestions
|
||||
WHERE event_id = ${event.id} AND origin_run_id IN (${placeholders})
|
||||
GROUP BY origin_run_id`
|
||||
);
|
||||
// Single SQL query for all listed runs (using parameterized query to prevent SQL injection)
|
||||
const aggRows = await prisma.$queryRaw`
|
||||
SELECT origin_run_id AS "originRunId",
|
||||
COUNT(*)::int AS "totalSuggestions",
|
||||
COUNT(*) FILTER (WHERE recorder_id IS NOT NULL)::int AS "assignedCount",
|
||||
COUNT(*) FILTER (WHERE status = 'not_found')::int AS "notFoundCount"
|
||||
FROM recording_suggestions
|
||||
WHERE event_id = ${event.id} AND origin_run_id = ANY(${runIds})
|
||||
GROUP BY origin_run_id
|
||||
`;
|
||||
const aggByRun = new Map(aggRows.map(r => [r.originRunId, r]));
|
||||
for (const r of runs) {
|
||||
const agg = aggByRun.get(r.id) || { totalSuggestions: 0, assignedCount: 0, notFoundCount: 0 };
|
||||
|
||||
Reference in New Issue
Block a user