From 825c61df8e37539be02ac427b6c9730a29d11a32 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 11 Mar 2026 11:35:42 +0530 Subject: [PATCH 1/2] fix: remove em dashes, fix mojibake, fix claim toast UUID, fix notification read persistence, fix unread count template --- backend/src/auth/auth.service.ts | 2 +- backend/src/auth/entities/user.entity.ts | 2 +- backend/src/auth/tests/jwt-security.spec.ts | 10 ++--- backend/src/common/cloudinary.service.ts | 2 +- backend/src/common/email.service.ts | 4 +- .../notifications/notifications.controller.ts | 6 +-- backend/src/scripts/backup_db.sh | 2 +- backend/test/realtime-events.e2e-spec.ts | 8 ++-- frontend/e2e/donation-lifecycle.spec.ts | 6 +-- frontend/playwright.config.ts | 2 +- frontend/src/App.css | 2 +- .../pages/dashboard/AdminDashboard.test.tsx | 2 +- frontend/src/i18n.ts | 40 +++++++++---------- frontend/src/locales/hi.ts | 24 +++++------ frontend/src/locales/ta.ts | 24 +++++------ frontend/src/pages/LandingPage.tsx | 2 +- .../src/pages/dashboard/AdminDashboard.tsx | 4 +- frontend/src/pages/dashboard/DiscoveryMap.tsx | 19 ++++++--- .../src/pages/dashboard/FeedbackRatings.tsx | 2 +- frontend/src/pages/dashboard/History.tsx | 2 +- frontend/src/pages/dashboard/Impact.tsx | 12 +++--- frontend/src/pages/dashboard/NGODashboard.tsx | 21 ++++++---- frontend/src/pages/dashboard/Profile.tsx | 2 +- frontend/src/services/api.ts | 4 +- frontend/src/services/socket.ts | 2 +- frontend/src/services/translationService.ts | 2 +- 26 files changed, 111 insertions(+), 97 deletions(-) diff --git a/backend/src/auth/auth.service.ts b/backend/src/auth/auth.service.ts index ab29477c..1265a6c9 100644 --- a/backend/src/auth/auth.service.ts +++ b/backend/src/auth/auth.service.ts @@ -136,7 +136,7 @@ export class AuthService { }; } - // Shared badge catalog — must match donations.service.ts checkAndAwardBadges + // Shared badge catalog - must match donations.service.ts checkAndAwardBadges private static readonly BADGE_RULES = [ { threshold: 10, diff --git a/backend/src/auth/entities/user.entity.ts b/backend/src/auth/entities/user.entity.ts index f807794f..1d844a2f 100644 --- a/backend/src/auth/entities/user.entity.ts +++ b/backend/src/auth/entities/user.entity.ts @@ -88,7 +88,7 @@ export class User { @Column('simple-array', { default: '' }) badges: string[]; - // Timestamps — only once each ✅ + // Timestamps - only once each ✅ @CreateDateColumn() createdAt: Date; diff --git a/backend/src/auth/tests/jwt-security.spec.ts b/backend/src/auth/tests/jwt-security.spec.ts index fcf6c48b..beb341c7 100644 --- a/backend/src/auth/tests/jwt-security.spec.ts +++ b/backend/src/auth/tests/jwt-security.spec.ts @@ -1,6 +1,6 @@ import * as jwt from 'jsonwebtoken'; -// Uses the same signing approach as your JwtStrategy — only the secret matters. +// Uses the same signing approach as your JwtStrategy - only the secret matters. // These tests run standalone: npx jest jwt-security --no-coverage const SECRET = 'test-jwt-secret-for-security-tests'; @@ -74,22 +74,22 @@ describe('JWT Security', () => { expiresIn: '1h', }); const decoded = jwt.verify(donorToken, SECRET) as any; - // Role must stay DONOR — attacker cannot change it without re-signing + // Role must stay DONOR - attacker cannot change it without re-signing expect(decoded.role).toBe('DONOR'); expect(decoded.role).not.toBe('ADMIN'); }); // ── 7. Token reuse (stateless note) ────────────────────────────────────── - // JWTs are stateless — a valid token stays valid until expiry. + // JWTs are stateless - a valid token stays valid until expiry. // To truly block reuse after logout, a Redis blacklist is required. // This test documents the known gap: it('documents that stateless JWT cannot be invalidated before expiry without a blacklist', () => { const token = jwt.sign({ sub: 'user-abc', role: 'DONOR' }, SECRET, { expiresIn: '1h', }); - // Simulate logout — but the token is still cryptographically valid + // Simulate logout - but the token is still cryptographically valid const decoded = jwt.verify(token, SECRET) as any; - // Without a blacklist check, this still passes — expected behaviour to document + // Without a blacklist check, this still passes - expected behaviour to document expect(decoded.sub).toBe('user-abc'); // RECOMMENDATION: Add Redis token blacklist in JwtAuthGuard for full logout security }); diff --git a/backend/src/common/cloudinary.service.ts b/backend/src/common/cloudinary.service.ts index a818b5be..0b5d46d6 100644 --- a/backend/src/common/cloudinary.service.ts +++ b/backend/src/common/cloudinary.service.ts @@ -35,7 +35,7 @@ export class CloudinaryService { async uploadImage(file: Express.Multer.File): Promise { if (this.isMockMode) { this.logger.warn( - `Mock upload for "${file.originalname}" — Cloudinary not configured`, + `Mock upload for "${file.originalname}" - Cloudinary not configured`, ); return this.getMockUrl(file.originalname); } diff --git a/backend/src/common/email.service.ts b/backend/src/common/email.service.ts index 7f18aaca..0559f708 100644 --- a/backend/src/common/email.service.ts +++ b/backend/src/common/email.service.ts @@ -42,7 +42,7 @@ export class EmailService { if (!this.isConfigured || !this.transporter) { // Explicit log so devs know emails are not being sent this.logger.warn( - `[EMAIL NOT SENT — no SMTP config]\n To: ${to}\n Subject: ${subject}`, + `[EMAIL NOT SENT - no SMTP config]\n To: ${to}\n Subject: ${subject}`, ); return; } @@ -57,7 +57,7 @@ export class EmailService { this.logger.log(`✅ Email sent to ${to}: "${subject}"`); } catch (error) { this.logger.error(`❌ Failed to send email to ${to}: ${error.message}`); - // Don't throw — email failure should never crash the main flow + // Don't throw - email failure should never crash the main flow } } diff --git a/backend/src/notifications/notifications.controller.ts b/backend/src/notifications/notifications.controller.ts index 757f93ea..1ba6cf86 100644 --- a/backend/src/notifications/notifications.controller.ts +++ b/backend/src/notifications/notifications.controller.ts @@ -20,20 +20,20 @@ export class NotificationsController { @Get() @ApiOperation({ summary: 'Get current user notifications' }) async getMyNotifications(@Request() req: any) { - return this.notificationsService.findByUser(req.user.sub); + return this.notificationsService.findByUser(req.user.userId); } @Patch(':id/read') @ApiOperation({ summary: 'Mark a notification as read' }) async markRead(@Param('id') id: string, @Request() req: any) { - await this.notificationsService.markRead(id, req.user.sub); + await this.notificationsService.markRead(id, req.user.userId); return { success: true }; } @Patch('read-all') @ApiOperation({ summary: 'Mark all notifications as read' }) async markAllRead(@Request() req: any) { - await this.notificationsService.markAllRead(req.user.sub); + await this.notificationsService.markAllRead(req.user.userId); return { success: true }; } } diff --git a/backend/src/scripts/backup_db.sh b/backend/src/scripts/backup_db.sh index 72b6e6aa..e98eab42 100644 --- a/backend/src/scripts/backup_db.sh +++ b/backend/src/scripts/backup_db.sh @@ -35,7 +35,7 @@ else exit 1 fi -# 3. Rotate old backups — keep only the last MAX_BACKUPS files +# 3. Rotate old backups - keep only the last MAX_BACKUPS files BACKUP_COUNT=$(ls -1 "$BACKUP_DIR"/*.sql 2>/dev/null | wc -l) if [ "$BACKUP_COUNT" -gt "$MAX_BACKUPS" ]; then echo "🧹 Rotating old backups (keeping last $MAX_BACKUPS)..." diff --git a/backend/test/realtime-events.e2e-spec.ts b/backend/test/realtime-events.e2e-spec.ts index b102f30c..329036d9 100644 --- a/backend/test/realtime-events.e2e-spec.ts +++ b/backend/test/realtime-events.e2e-spec.ts @@ -194,7 +194,7 @@ describeIfServer('Real-Time Events – Socket.IO Client Tests', () => { expect(ngoEvent.data).toHaveProperty('name'); expect(volunteerEvent.data).toHaveProperty('name'); - // Latency check — event should arrive quickly + // Latency check - event should arrive quickly // Docker networking adds overhead; allow up to 500 ms const maxLatency = 500; expect(ngoEvent.latencyMs).toBeLessThan(maxLatency); @@ -257,7 +257,7 @@ describeIfServer('Real-Time Events – Socket.IO Client Tests', () => { expect(volunteerEvent.data).toHaveProperty('donationId'); expect(volunteerEvent.data.status).toBe('CLAIMED'); - // Latency check — Docker networking adds overhead; allow up to 500 ms + // Latency check - Docker networking adds overhead; allow up to 500 ms const maxLatency = 500; expect(donorEvent.latencyMs).toBeLessThan(maxLatency); expect(volunteerEvent.latencyMs).toBeLessThan(maxLatency); @@ -311,7 +311,7 @@ describeIfServer('Real-Time Events – Socket.IO Client Tests', () => { const maxLatency = 500; expect(latencyMs).toBeLessThan(maxLatency); } catch { - // Auto-assign may not fire if no volunteer is nearby — that's acceptable + // Auto-assign may not fire if no volunteer is nearby - that's acceptable console.warn('volunteer.assigned not received (no eligible volunteer nearby)'); } }, 15_000); @@ -426,7 +426,7 @@ describe('EventsGateway – NestJS Integration', () => { setTimeout(() => reject(new Error('Connection timeout')), 5_000); }); } catch { - // AppModule may not compile without database — skip gracefully + // AppModule may not compile without database - skip gracefully console.warn('Skipping NestJS integration tests (AppModule requires database)'); } }, 30_000); diff --git a/frontend/e2e/donation-lifecycle.spec.ts b/frontend/e2e/donation-lifecycle.spec.ts index 2d2cf5a3..b7307b80 100644 --- a/frontend/e2e/donation-lifecycle.spec.ts +++ b/frontend/e2e/donation-lifecycle.spec.ts @@ -148,7 +148,7 @@ test.describe('Donation Lifecycle – Full E2E', () => { await mapContainer.scrollIntoViewIfNeeded(); await page.waitForTimeout(2_000); - // Click the map — offset from top-left to avoid zoom controls + // Click the map - offset from top-left to avoid zoom controls const box = await mapContainer.boundingBox(); if (box) { await page.mouse.click(box.x + box.width * 0.6, box.y + box.height * 0.5); @@ -178,7 +178,7 @@ test.describe('Donation Lifecycle – Full E2E', () => { if (hook.queue && hook.memoizedState === null && idx > 0) { const dispatch = hook.queue.dispatch; if (typeof dispatch === 'function') { - // Try setting it — if this is the right hook, it'll set location + // Try setting it - if this is the right hook, it'll set location dispatch({ lat: 28.6139, lng: 77.2090 }); return true; } @@ -204,7 +204,7 @@ test.describe('Donation Lifecycle – Full E2E', () => { // Wait a moment for state to update await page.waitForTimeout(500); - // Submit the form — button should now be enabled + // Submit the form - button should now be enabled const submitBtn = page.getByRole('button', { name: /add food/i }); await expect(submitBtn).toBeEnabled({ timeout: 15_000 }); await submitBtn.click(); diff --git a/frontend/playwright.config.ts b/frontend/playwright.config.ts index e5295e57..4bb496c2 100644 --- a/frontend/playwright.config.ts +++ b/frontend/playwright.config.ts @@ -3,7 +3,7 @@ import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: './e2e', globalSetup: './e2e/global-setup.ts', - fullyParallel: false, // Run tests sequentially — donation lifecycle depends on order + fullyParallel: false, // Run tests sequentially - donation lifecycle depends on order forbidOnly: !!process.env.CI, retries: process.env.CI ? 1 : 0, workers: 1, diff --git a/frontend/src/App.css b/frontend/src/App.css index 16b5bb8e..d93ee8ed 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -1,2 +1,2 @@ -/* App.css intentionally removed — using Tailwind for styles */ +/* App.css intentionally removed - using Tailwind for styles */ diff --git a/frontend/src/__tests__/pages/dashboard/AdminDashboard.test.tsx b/frontend/src/__tests__/pages/dashboard/AdminDashboard.test.tsx index 581d388e..63d98105 100644 --- a/frontend/src/__tests__/pages/dashboard/AdminDashboard.test.tsx +++ b/frontend/src/__tests__/pages/dashboard/AdminDashboard.test.tsx @@ -96,7 +96,7 @@ describe('AdminDashboard - Epic 7 User Story 1 & 2', () => { await waitFor(() => { expect(adminAPI.verifyNGO).toHaveBeenCalledWith('ngo-123'); - expect(toast.success).toHaveBeenCalledWith('NGO verified — email sent'); + expect(toast.success).toHaveBeenCalledWith('NGO verified - email sent'); }); }); }); diff --git a/frontend/src/i18n.ts b/frontend/src/i18n.ts index d47e4ee6..3a7a8da5 100644 --- a/frontend/src/i18n.ts +++ b/frontend/src/i18n.ts @@ -3,7 +3,7 @@ import { initReactI18next } from 'react-i18next'; import hiStrings from './locales/hi'; import taStrings from './locales/ta'; -//─ English source strings (the ONLY static dictionary)─ +//─ English source strings (the ONLY static dictionary)─ // Every other language is translated dynamically via API and cached in localStorage. export const enStrings: Record = { @@ -81,11 +81,11 @@ export const enStrings: Record = { stepDeliverDesc: 'Food reaches the community through NGOs', threeRolesOneMission: 'Three roles, one mission', everyoneHasAPart: 'Everyone has a part to play', - donorSubtitle: 'Restaurants · Caterers · Individuals', + donorSubtitle: 'Restaurants · Caterers · Individuals', donorDesc: 'List surplus food in seconds. Upload photos, set quantities, and our safety engine auto-calculates expiry windows.', - ngoSubtitle: 'Food banks · Shelters · Charities', + ngoSubtitle: 'Food banks · Shelters · Charities', ngoDesc: 'Discover nearby donations on a live map. Claim food, track pickups, and manage your daily intake capacity.', - volunteerSubtitle: 'Drivers · Students · Community', + volunteerSubtitle: 'Drivers · Students · Community', volunteerDesc: 'Pick up claimed food from donors and deliver it to NGOs. Track your deliveries and build your impact score.', avgListingTime: 'Avg listing time', safetyValidated: 'Safety validated', @@ -110,7 +110,7 @@ export const enStrings: Record = { liveStatusTracking: 'Live status tracking', liveStatusDesc: 'Follow every donation from listing to delivery with real-time status updates.', impactDashboard: 'Impact dashboard', - impactDashboardDesc: 'Every meal saved is tracked. See your contribution to reducing COâ‚‚ emissions, total meals redistributed, and community impact over time.', + impactDashboardDesc: 'Every meal saved is tracked. See your contribution to reducing CO₂ emissions, total meals redistributed, and community impact over time.', emissionsTracked: 'Emissions tracked', perDonation: 'Per donation', foodSaved: 'Food saved', @@ -231,10 +231,10 @@ export const enStrings: Record = { descriptionPlaceholder: 'Any additional details (ingredients, dietary info, special instructions)...', foodImages: 'Food Images (Optional)', pickupLocationLabel: 'Pickup Location', - locationSelected: '✓ Selected', + locationSelected: '✓ Selected', clickMapToSet: 'Click on the map to set pickup location', hygieneChecklist: 'Hygiene Checklist', - hygieneComplete: '✓ Complete', + hygieneComplete: '✓ Complete', keptCoveredAlways: 'Food was kept covered at all times', cleanFoodSafe: 'Container is clean and food-safe', hygieneNote: 'Both hygiene requirements must be met to ensure food safety', @@ -298,24 +298,24 @@ export const enStrings: Record = { nextBadge: 'Next: {{name}}', pointsToGo: '{{points}} pts to go', allBadgesUnlocked: 'All badges unlocked! You\'re a Superhero!', - communityImpact: 'Community Impact — Platform Wide', + communityImpact: 'Community Impact - Platform Wide', communityImpactDesc: 'Live totals across all donors, NGOs and volunteers on SurplusSync', - co2Saved: 'COâ‚‚ Saved', + co2Saved: 'CO₂ Saved', totalDonationsProcessed: '{{count}} total donations processed', successfullyDelivered: '{{count}} successfully delivered', currentlyActive: '{{count}} currently active', ngoGrowthReports: 'NGO Growth Reports', lastSixMonths: 'Last 6 months', - monthlyIntakeSummaries: 'Monthly food intake summaries — use these for grant and funding applications', + monthlyIntakeSummaries: 'Monthly food intake summaries - use these for grant and funding applications', totalReceivedMonth: 'Total donations received each month', deliveryTrend: 'Delivery Trend', deliveriesPerMonth: 'Successful food deliveries per month', claimsEachMonth: 'Donations claimed each month', - highDeliveryTip: 'A high delivery rate demonstrates operational efficiency — highlight this in funding applications', + highDeliveryTip: 'A high delivery rate demonstrates operational efficiency - highlight this in funding applications', // Notifications stayUpdated: 'Stay updated on your donations and deliveries', - unread: 'Unread {{count}}', + unread: 'Unread', markAllRead: 'Mark all as read', loadingNotifications: 'Loading notifications...', noUnreadNotifications: 'No unread notifications', @@ -331,7 +331,7 @@ export const enStrings: Record = { backToLogin: 'Back to Login', manageAccount: 'Manage your account and view your impact', download: 'Download', - levelContributor: 'Level {{level}} • {{role}}', + levelContributor: 'Level {{level}} • {{role}}', progressToLevel: 'Progress to Level {{level}}', pointsToGoProfile: '{{points}} points to go', trophyCase: 'Trophy Case', @@ -343,7 +343,7 @@ export const enStrings: Record = { notProvided: 'Not provided', badgeGuide: 'Badge Guide', earnKarma: 'Earn {{points}} karma points', - earned: '✓ Earned', + earned: '✓ Earned', howToEarnKarma: 'How to Earn Karma', createDonation: 'Create a Donation', createDonationDesc: 'Donor lists new food for redistribution', @@ -387,7 +387,7 @@ export const enStrings: Record = { activeTasks: 'Active Tasks', completedTrips: 'Completed Trips', noActiveTasks: 'No active tasks', - waitingForAssignment: "You're available — waiting for assignment", + waitingForAssignment: "You're available - waiting for assignment", toggleAvailabilityHint: 'Toggle your availability to receive assignments', enRoute: 'En Route', awaitingPickup: 'Awaiting Pickup', @@ -473,11 +473,11 @@ export const enStrings: Record = { karmaPointsLevel: '⭐ {{karma}} Karma Points · Level {{level}} Contributor', // NGOGrowthCharts (alternate key names used by component) - ngoGrowthSubtitle: 'Monthly food intake summaries — use these for grant and funding applications', + ngoGrowthSubtitle: 'Monthly food intake summaries - use these for grant and funding applications', totalDonationsReceivedMonth: 'Total donations received each month', successfulDeliveriesPerMonth: 'Successful food deliveries per month', donationsClaimedMonth: 'Donations claimed each month', - highDeliveryRateTip: '💡 A high delivery rate demonstrates operational efficiency — highlight this in funding applications', + highDeliveryRateTip: '💡 A high delivery rate demonstrates operational efficiency - highlight this in funding applications', // Profile karma actions deliverDonation: 'Deliver Donation', @@ -539,7 +539,7 @@ export const enStrings: Record = { // ── Accessibility extras ── translating: 'Translating...', translatingProgress: 'Translating... {{done}}/{{total}}', - firstTimeTranslation: 'First-time translation — cached for instant loading next time', + firstTimeTranslation: 'First-time translation - cached for instant loading next time', toggleHighContrastDesc: 'Toggle high-contrast dark mode for improved readability.', translationCache: 'Translation Cache', translationCacheDesc: 'Translations are cached locally for instant loading. Clear the cache to re-translate.', @@ -599,7 +599,7 @@ export const enStrings: Record = { // ── Near-Expiry Alerts ── nearExpiryAlerts: 'Near-Expiry Alerts', - nearExpiryDesc: 'Donations expiring within 2 hours — act fast to prevent waste.', + nearExpiryDesc: 'Donations expiring within 2 hours - act fast to prevent waste.', refresh: 'Refresh', urgencyFilter: 'Urgency Filter', critical: 'Critical', @@ -654,7 +654,7 @@ export const enStrings: Record = { loadingTickets: 'Loading tickets…', noTicketsYet: 'No tickets yet. Create one to get started.', advance: 'Advance', - ticketSubmitted: 'Ticket submitted — you will receive an email confirmation', + ticketSubmitted: 'Ticket submitted - you will receive an email confirmation', failedLoadTickets: 'Failed to load tickets', failedSubmitTicket: 'Failed to submit ticket', failedUpdateTicket: 'Failed to update ticket', diff --git a/frontend/src/locales/hi.ts b/frontend/src/locales/hi.ts index 640e2378..85545d03 100644 --- a/frontend/src/locales/hi.ts +++ b/frontend/src/locales/hi.ts @@ -1,4 +1,4 @@ -// Hindi (हिन्दी) — Complete static translation dictionary +// Hindi (हिन्दी) - Complete static translation dictionary const hi: Record = { // —— Common / Shared —— @@ -292,7 +292,7 @@ const hi: Record = { nextBadge: 'अगला: {{name}}', pointsToGo: '{{points}} पॉइंट्स बाकी', allBadgesUnlocked: 'सभी बैज अनलॉक हो गए! आप सुपरहीरो हैं!', - communityImpact: 'सामुदायिक प्रभाव — प्लेटफ़ॉर्म व्यापी', + communityImpact: 'सामुदायिक प्रभाव - प्लेटृफ़ॉर्म व्यापी', communityImpactDesc: 'SurplusSync पर सभी दानदाताओं, एनजीओ और स्वयंसेवकों का लाइव कुल', co2Saved: 'CO₂ बचाया', totalDonationsProcessed: '{{count}} कुल दान प्रोसेस किए', @@ -300,16 +300,16 @@ const hi: Record = { currentlyActive: '{{count}} वर्तमान में सक्रिय', ngoGrowthReports: 'एनजीओ विकास रिपोर्ट', lastSixMonths: 'पिछले 6 महीने', - monthlyIntakeSummaries: 'मासिक खाद्य ग्रहण सारांश — इन्हें अनुदान और फंडिंग आवेदनों के लिए उपयोग करें', + monthlyIntakeSummaries: 'मासिक खाद्य ग्रहण सारांश - इन्हें अनुदान और फंडिंग आवेदनों के लिए उपयोग करें', totalReceivedMonth: 'प्रत्येक माह प्राप्त कुल दान', deliveryTrend: 'डिलीवरी रुझान', deliveriesPerMonth: 'प्रति माह सफल खाद्य डिलीवरी', claimsEachMonth: 'प्रत्येक माह क्लेम किए गए दान', - highDeliveryTip: 'उच्च डिलीवरी दर परिचालन दक्षता प्रदर्शित करती है — फंडिंग आवेदनों में इसे हाइलाइट करें', + highDeliveryTip: 'उच्च डिलीवरी दर परिचालन दक्षता प्रदर्शित करती है - फंडिंग आवेदनों में इसे हाइलाइट करें', // —— Notifications —— stayUpdated: 'अपने दान और डिलीवरी पर अपडेट रहें', - unread: 'अपठित {{count}}', + unread: 'अपठित', markAllRead: 'सभी को पढ़ा हुआ चिह्नित करें', loadingNotifications: 'सूचनाएँ लोड हो रही हैं...', noUnreadNotifications: 'कोई अपठित सूचना नहीं', @@ -381,7 +381,7 @@ const hi: Record = { activeTasks: 'सक्रिय कार्य', completedTrips: 'पूर्ण यात्राएँ', noActiveTasks: 'कोई सक्रिय कार्य नहीं', - waitingForAssignment: 'आप उपलब्ध हैं — असाइनमेंट की प्रतीक्षा में', + waitingForAssignment: 'आप उपलब्ध हैं - असाइनमेंट की प्रतीक्षा में', toggleAvailabilityHint: 'असाइनमेंट प्राप्त करने के लिए अपनी उपलब्धता टॉगल करें', enRoute: 'रास्ते में', awaitingPickup: 'पिकअप की प्रतीक्षा', @@ -467,11 +467,11 @@ const hi: Record = { karmaPointsLevel: '⭐ {{karma}} कर्मा पॉइंट्स · लेवल {{level}} योगदानकर्ता', // NGOGrowthCharts - ngoGrowthSubtitle: 'मासिक खाद्य ग्रहण सारांश — इन्हें अनुदान और फंडिंग आवेदनों के लिए उपयोग करें', + ngoGrowthSubtitle: 'मासिक खाद्य ग्रहण सारांश - इन्हें अनुदान और फंडिंग आवेदनों के लिए उपयोग करें', totalDonationsReceivedMonth: 'प्रत्येक माह प्राप्त कुल दान', successfulDeliveriesPerMonth: 'प्रति माह सफल खाद्य डिलीवरी', donationsClaimedMonth: 'प्रत्येक माह क्लेम किए गए दान', - highDeliveryRateTip: '💡 उच्च डिलीवरी दर परिचालन दक्षता प्रदर्शित करती है — फंडिंग आवेदनों में इसे हाइलाइट करें', + highDeliveryRateTip: '💡 उच्च डिलीवरी दर परिचालन दक्षता प्रदर्शित करती है - फंडिंग आवेदनों में इसे हाइलाइट करें', // Profile karma actions deliverDonation: 'दान डिलीवर करें', @@ -533,7 +533,7 @@ const hi: Record = { // —— Accessibility extras —— translating: 'अनुवाद हो रहा है...', translatingProgress: 'अनुवाद... {{done}}/{{total}}', - firstTimeTranslation: 'पहली बार अनुवाद — अगली बार तुरंत लोडिंग के लिए कैश किया गया', + firstTimeTranslation: 'पहली बार अनुवाद - अगली बार तुरंत लोडिंग के लिए कैश किया गया', toggleHighContrastDesc: 'बेहतर पठनीयता के लिए हाई-कॉन्ट्रास्ट डार्क मोड टॉगल करें।', translationCache: 'अनुवाद कैश', translationCacheDesc: 'अनुवाद तुरंत लोडिंग के लिए स्थानीय रूप से कैश किए जाते हैं। पुनः अनुवाद करने के लिए कैश साफ़ करें।', @@ -593,7 +593,7 @@ const hi: Record = { // —— Near-Expiry Alerts —— nearExpiryAlerts: 'समाप्ति निकट अलर्ट', - nearExpiryDesc: '2 घंटे के भीतर समाप्त होने वाले दान — बर्बादी रोकने के लिए जल्दी कार्रवाई करें।', + nearExpiryDesc: '2 घंटे के भीतर समाप्त होने वाले दान - बर्बादी रोकने के लिए जल्दी कार्रवाई करें।', refresh: 'रिफ़्रेश', urgencyFilter: 'तात्कालिकता फ़िल्टर', critical: 'गंभीर', @@ -615,7 +615,7 @@ const hi: Record = { // —— Feedback & Ratings —— ngoFeedbackRatings: 'एनजीओ प्रतिक्रिया और रेटिंग', - feedbackDesc: 'डिलीवरी के बाद की प्रतिक्रिया — भोजन गुणवत्ता और दानदाता विश्वसनीयता ट्रैक करें।', + feedbackDesc: 'डिलीवरी के बाद की प्रतिक्रिया - भोजन गुणवत्ता और दानदाता विश्वसनीयता ट्रैक करें।', yourDonorRating: 'आपकी दानदाता रेटिंग', basedOnReviews: 'एनजीओ की {{count}} समीक्षाओं पर आधारित', leaveReview: 'समीक्षा लिखें', @@ -648,7 +648,7 @@ const hi: Record = { loadingTickets: 'टिकट लोड हो रहे हैं…', noTicketsYet: 'अभी तक कोई टिकट नहीं। शुरू करने के लिए एक बनाएँ।', advance: 'आगे बढ़ाएँ', - ticketSubmitted: 'टिकट सबमिट किया गया — आपको ईमेल पुष्टि प्राप्त होगी', + ticketSubmitted: 'टिकट सबमिट किया गया - आपको ईमेल पुष्टि प्राप्त होगी', failedLoadTickets: 'टिकट लोड करने में विफल', failedSubmitTicket: 'टिकट सबमिट करने में विफल', failedUpdateTicket: 'टिकट अपडेट करने में विफल', diff --git a/frontend/src/locales/ta.ts b/frontend/src/locales/ta.ts index 1e03b14c..575af3da 100644 --- a/frontend/src/locales/ta.ts +++ b/frontend/src/locales/ta.ts @@ -1,4 +1,4 @@ -// Tamil (தமிழ்) — Complete static translation dictionary +// Tamil (தமிழ்) - Complete static translation dictionary const ta: Record = { // —— Common / Shared —— @@ -292,7 +292,7 @@ const ta: Record = { nextBadge: 'அடுத்தது: {{name}}', pointsToGo: '{{points}} புள்ளிகள் மீதம்', allBadgesUnlocked: 'அனைத்து பேட்ஜ்களும் திறக்கப்பட்டன! நீங்கள் ஒரு சூப்பர் ஹீரோ!', - communityImpact: 'சமூக தாக்கம் — தளம் முழுவதும்', + communityImpact: 'சமூக தாக்கம் - தளம் முழுவதும்', communityImpactDesc: 'SurplusSync-இல் உள்ள அனைத்து நன்கொடையாளர்கள், NGO-கள் மற்றும் தன்னார்வலர்களின் நிகழ்நேர மொத்தங்கள்', co2Saved: 'CO₂ சேமிப்பு', totalDonationsProcessed: '{{count}} மொத்த நன்கொடைகள் செயலாக்கப்பட்டன', @@ -300,16 +300,16 @@ const ta: Record = { currentlyActive: '{{count}} தற்போது செயலில்', ngoGrowthReports: 'NGO வளர்ச்சி அறிக்கைகள்', lastSixMonths: 'கடந்த 6 மாதங்கள்', - monthlyIntakeSummaries: 'மாதாந்திர உணவு உள்ளெடுப்பு சுருக்கங்கள் — மானியம் மற்றும் நிதி விண்ணப்பங்களுக்கு இவற்றைப் பயன்படுத்துங்கள்', + monthlyIntakeSummaries: 'மாதாந்திர உணவு உள்ளெடுப்பு சுருக்கங்கள் - மானியம் மற்றும் நிதி விண்ணப்பங்களுக்கு இவற்றைப் பயன்படுத்துங்கள்', totalReceivedMonth: 'ஒவ்வொரு மாதமும் பெறப்பட்ட மொத்த நன்கொடைகள்', deliveryTrend: 'டெலிவரி போக்கு', deliveriesPerMonth: 'மாதத்திற்கு வெற்றிகரமான உணவு டெலிவரிகள்', claimsEachMonth: 'ஒவ்வொரு மாதமும் கோரப்பட்ட நன்கொடைகள்', - highDeliveryTip: 'உயர் டெலிவரி விகிதம் செயல்பாட்டு திறனை நிரூபிக்கிறது — நிதி விண்ணப்பங்களில் இதை முன்னிலைப்படுத்துங்கள்', + highDeliveryTip: 'உயர் டெலிவரி விகிதம் செயல்பாட்டு திறனை நிரூபிக்கிறது - நிதி விண்ணப்பங்களில் இதை முன்னிலைப்படுத்துங்கள்', // —— Notifications —— stayUpdated: 'உங்கள் நன்கொடைகள் மற்றும் டெலிவரிகளில் புதுப்பித்திருங்கள்', - unread: 'படிக்காதவை {{count}}', + unread: 'படிக்காதவை', markAllRead: 'அனைத்தையும் படித்ததாகக் குறி', loadingNotifications: 'அறிவிப்புகள் ஏற்றப்படுகின்றன...', noUnreadNotifications: 'படிக்காத அறிவிப்புகள் இல்லை', @@ -381,7 +381,7 @@ const ta: Record = { activeTasks: 'செயலில் உள்ள பணிகள்', completedTrips: 'முடிக்கப்பட்ட பயணங்கள்', noActiveTasks: 'செயலில் உள்ள பணிகள் இல்லை', - waitingForAssignment: 'நீங்கள் கிடைக்கிறீர்கள் — ஒதுக்கீட்டுக்கு காத்திருக்கிறது', + waitingForAssignment: 'நீங்கள் கிடைக்கிறீர்கள் - ஒதுக்கீட்டுக்கு காத்திருக்கிறது', toggleAvailabilityHint: 'ஒதுக்கீடுகளைப் பெற உங்கள் கிடைக்கும் நிலையை மாற்றவும்', enRoute: 'வழியில்', awaitingPickup: 'பிக்கப் காத்திருக்கிறது', @@ -467,11 +467,11 @@ const ta: Record = { karmaPointsLevel: '⭐ {{karma}} கர்மா புள்ளிகள் · நிலை {{level}} பங்களிப்பாளர்', // NGOGrowthCharts - ngoGrowthSubtitle: 'மாதாந்திர உணவு உள்ளெடுப்பு சுருக்கங்கள் — மானியம் மற்றும் நிதி விண்ணப்பங்களுக்கு இவற்றைப் பயன்படுத்துங்கள்', + ngoGrowthSubtitle: 'மாதாந்திர உணவு உள்ளெடுப்பு சுருக்கங்கள் - மானியம் மற்றும் நிதி விண்ணப்பங்களுக்கு இவற்றைப் பயன்படுத்துங்கள்', totalDonationsReceivedMonth: 'ஒவ்வொரு மாதமும் பெறப்பட்ட மொத்த நன்கொடைகள்', successfulDeliveriesPerMonth: 'மாதத்திற்கு வெற்றிகரமான உணவு டெலிவரிகள்', donationsClaimedMonth: 'ஒவ்வொரு மாதமும் கோரப்பட்ட நன்கொடைகள்', - highDeliveryRateTip: '💡 உயர் டெலிவரி விகிதம் செயல்பாட்டுத் திறனை நிரூபிக்கிறது — நிதி விண்ணப்பங்களில் இதை முன்னிலைப்படுத்துங்கள்', + highDeliveryRateTip: '💡 உயர் டெலிவரி விகிதம் செயல்பாட்டுத் திறனை நிரூபிக்கிறது - நிதி விண்ணப்பங்களில் இதை முன்னிலைப்படுத்துங்கள்', // Profile karma actions deliverDonation: 'நன்கொடையை வழங்கு', @@ -533,7 +533,7 @@ const ta: Record = { // —— Accessibility extras —— translating: 'மொழிபெயர்க்கிறது...', translatingProgress: 'மொழிபெயர்ப்பு... {{done}}/{{total}}', - firstTimeTranslation: 'முதல் முறை மொழிபெயர்ப்பு — அடுத்த முறை உடனடி ஏற்றத்திற்காக தற்காலிகமாகச் சேமிக்கப்பட்டது', + firstTimeTranslation: 'முதல் முறை மொழிபெயர்ப்பு - அடுத்த முறை உடனடி ஏற்றத்திற்காக தற்காலிகமாகச் சேமிக்கப்பட்டது', toggleHighContrastDesc: 'மேம்பட்ட படிக்கும் திறனுக்கு உயர்-மாறுபாடு இருண்ட பயன்முறையை மாற்றவும்.', translationCache: 'மொழிபெயர்ப்பு கேச்', translationCacheDesc: 'மொழிபெயர்ப்புகள் உடனடி ஏற்றத்திற்காக உள்ளூரில் தற்காலிகமாகச் சேமிக்கப்படுகின்றன. மீண்டும் மொழிபெயர்க்க கேச்சை அழிக்கவும்.', @@ -593,7 +593,7 @@ const ta: Record = { // —— Near-Expiry Alerts —— nearExpiryAlerts: 'காலாவதி நெருங்கும் எச்சரிக்கைகள்', - nearExpiryDesc: '2 மணி நேரத்திற்குள் காலாவதியாகும் நன்கொடைகள் — வீணாவதைத் தடுக்க விரைவாக செயல்படுங்கள்.', + nearExpiryDesc: '2 மணி நேரத்திற்குள் காலாவதியாகும் நன்கொடைகள் - வீணாவதைத் தடுக்க விரைவாக செயல்படுங்கள்.', refresh: 'புதுப்பி', urgencyFilter: 'அவசர வடிகட்டி', critical: 'அவசரம்', @@ -615,7 +615,7 @@ const ta: Record = { // —— Feedback & Ratings —— ngoFeedbackRatings: 'NGO கருத்து மற்றும் மதிப்பீடுகள்', - feedbackDesc: 'டெலிவரிக்குப் பிறகான கருத்து — உணவு தரம் மற்றும் நன்கொடையாளர் நம்பகத்தன்மையைக் கண்காணிக்கவும்.', + feedbackDesc: 'டெலிவரிக்குப் பிறகான கருத்து - உணவு தரம் மற்றும் நன்கொடையாளர் நம்பகத்தன்மையைக் கண்காணிக்கவும்.', yourDonorRating: 'உங்கள் நன்கொடையாளர் மதிப்பீடு', basedOnReviews: 'NGO-களின் {{count}} மதிப்புரை(களின்) அடிப்படையில்', leaveReview: 'மதிப்புரை எழுதுங்கள்', @@ -648,7 +648,7 @@ const ta: Record = { loadingTickets: 'டிக்கெட்டுகள் ஏற்றப்படுகின்றன…', noTicketsYet: 'இன்னும் டிக்கெட்டுகள் இல்லை. தொடங்க ஒன்றை உருவாக்குங்கள்.', advance: 'முன்னேற்று', - ticketSubmitted: 'டிக்கெட் சமர்ப்பிக்கப்பட்டது — மின்னஞ்சல் உறுதிப்படுத்தல் கிடைக்கும்', + ticketSubmitted: 'டிக்கெட் சமர்ப்பிக்கப்பட்டது - மின்னஞ்சல் உறுதிப்படுத்தல் கிடைக்கும்', failedLoadTickets: 'டிக்கெட்டுகளை ஏற்ற இயலவில்லை', failedSubmitTicket: 'டிக்கெட்டை சமர்ப்பிக்க இயலவில்லை', failedUpdateTicket: 'டிக்கெட்டை புதுப்பிக்க இயலவில்லை', diff --git a/frontend/src/pages/LandingPage.tsx b/frontend/src/pages/LandingPage.tsx index 97963a82..93d2d7dd 100644 --- a/frontend/src/pages/LandingPage.tsx +++ b/frontend/src/pages/LandingPage.tsx @@ -35,7 +35,7 @@ function useCountUp(target: number, duration = 2000) { } // Dat -// Data (keys only — translated inside component via t()) +// Data (keys only - translated inside component via t()) const roleConfigs = [ { titleKey: 'donor', diff --git a/frontend/src/pages/dashboard/AdminDashboard.tsx b/frontend/src/pages/dashboard/AdminDashboard.tsx index cff68b9e..f4f84d6b 100644 --- a/frontend/src/pages/dashboard/AdminDashboard.tsx +++ b/frontend/src/pages/dashboard/AdminDashboard.tsx @@ -79,7 +79,7 @@ function TicketModal({ ticket, onClose, onUpdate }: { setSaving(true); try { await adminAPI.updateTicket(ticket.id, { status, adminNote }); - toast.success('Ticket updated — user notified by email if resolved'); + toast.success('Ticket updated - user notified by email if resolved'); onUpdate(); onClose(); } catch { toast.error('Failed to update ticket'); } @@ -442,7 +442,7 @@ export default function AdminDashboard() { ) : userRole === 'ngo' && !isVerified ? (
- ⏳ {t('verificationPending')} — Cannot claim until verified. + ⏳ {t('verificationPending')} - Cannot claim until verified.
) : (
diff --git a/frontend/src/pages/dashboard/FeedbackRatings.tsx b/frontend/src/pages/dashboard/FeedbackRatings.tsx index b3fa4f9f..5e250bf4 100644 --- a/frontend/src/pages/dashboard/FeedbackRatings.tsx +++ b/frontend/src/pages/dashboard/FeedbackRatings.tsx @@ -165,7 +165,7 @@ export default function FeedbackRatings() { {unreviewedDonations.map(d => ( ))} diff --git a/frontend/src/pages/dashboard/History.tsx b/frontend/src/pages/dashboard/History.tsx index 0914ef7e..beea1379 100644 --- a/frontend/src/pages/dashboard/History.tsx +++ b/frontend/src/pages/dashboard/History.tsx @@ -286,7 +286,7 @@ export default function History() { ))}
- {/* Tab Toggle — Charts tab only for NGOs */} + {/* Tab Toggle - Charts tab only for NGOs */} {isNGO && (
- {/* Badge grid — all 5, earned/locked */} + {/* Badge grid - all 5, earned/locked */}
{catalog.map(b => { const isEarned = karma >= b.threshold @@ -553,7 +553,7 @@ export default function Impact() {

{pageSubtitle}

- {/* US1 — Personal Impact Stats */} + {/* US1 - Personal Impact Stats */}
{[ { label: stat1Label, value: stats.totalDonations, icon: , grad: 'from-emerald-500 to-emerald-600', accent: 'text-emerald-400', sub: role === 'donor' ? t('foodItemsShared') : t('completed') }, @@ -594,13 +594,13 @@ export default function Impact() {
- {/* US2 — Badges & Gamification */} + {/* US2 - Badges & Gamification */} - {/* US3/US5 — Community Counters */} + {/* US3/US5 - Community Counters */} {community && } - {/* US3/US5 — NGO Growth Charts */} + {/* US3/US5 - NGO Growth Charts */} {role === 'ngo' && monthly.length > 0 && } {/* Volunteer Performance (role-specific extra panel) */} @@ -616,7 +616,7 @@ export default function Impact() { )} - {/* US4 — Certificate CTA */} + {/* US4 - Certificate CTA */}
diff --git a/frontend/src/pages/dashboard/NGODashboard.tsx b/frontend/src/pages/dashboard/NGODashboard.tsx index aea9f29f..d91fa773 100644 --- a/frontend/src/pages/dashboard/NGODashboard.tsx +++ b/frontend/src/pages/dashboard/NGODashboard.tsx @@ -114,15 +114,17 @@ export default function NGODashboard() { // Listen for claimed donations const unsubscribeClaimed = socketService.onDonationClaimed((data) => { - // Remove the claimed donation from state and show its name + // Remove the claimed donation from state and show its name (skip toast for own claims) setDonations((prevDonations) => { const claimedDonation = prevDonations.find(d => d.id === data.donationId); - const name = claimedDonation ? claimedDonation.name : 'A donation'; - toast.info(`🔔 ${t('foodClaimedAlert')}`, { - description: `${name} has been claimed`, - duration: 3000, - }); + if (data.claimedBy !== user.id) { + const name = claimedDonation ? claimedDonation.name : 'A donation'; + toast.info(`🔔 ${t('foodClaimedAlert')}`, { + description: `${name} has been claimed`, + duration: 3000, + }); + } return prevDonations.filter((donation) => donation.id !== data.donationId); }) @@ -158,9 +160,14 @@ export default function NGODashboard() { } const handleClaim = async (donationId: string) => { + const donationName = donations.find(d => d.id === donationId)?.name || 'Donation'; setClaiming(donationId) try { await claimDonation(donationId) + toast.success(`✅ ${t('foodClaimedAlert')}`, { + description: `${donationName} has been claimed successfully`, + duration: 3000, + }) await load() setSelectedDonation(null) } catch (err: unknown) { @@ -542,7 +549,7 @@ export default function NGODashboard() {
{!user.isVerified ? (
- ⏳ {t('verificationPending')} — {t('verificationPendingDesc') || 'You cannot claim donations until your account is verified.'} + ⏳ {t('verificationPending')} - {t('verificationPendingDesc') || 'You cannot claim donations until your account is verified.'}
) : selectedDonation.status === 'AVAILABLE' ? (
- {/* Badge Guide — thresholds MUST match backend BADGE_RULES exactly */} + {/* Badge Guide - thresholds MUST match backend BADGE_RULES exactly */}

📚 {t('badgeGuide')}

diff --git a/frontend/src/services/api.ts b/frontend/src/services/api.ts index 9d10a343..877286be 100644 --- a/frontend/src/services/api.ts +++ b/frontend/src/services/api.ts @@ -17,7 +17,7 @@ api.interceptors.request.use((config: InternalAxiosRequestConfig) => { return config; }); -// Handle 401 responses — expired or invalid token → redirect to login +// Handle 401 responses - expired or invalid token → redirect to login api.interceptors.response.use( (response) => response, (error) => { @@ -341,7 +341,7 @@ export const markAsDelivered = async (id: string) => { return response.data; }; -// Notifications — persisted in backend DB +// Notifications - persisted in backend DB export interface RawNotification { id?: string; diff --git a/frontend/src/services/socket.ts b/frontend/src/services/socket.ts index ac6cff31..bff82fca 100644 --- a/frontend/src/services/socket.ts +++ b/frontend/src/services/socket.ts @@ -63,7 +63,7 @@ class SocketService { const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000'; - // Already connected — reuse existing socket + // Already connected - reuse existing socket if (this.socket?.connected) { return; } diff --git a/frontend/src/services/translationService.ts b/frontend/src/services/translationService.ts index 00e6bf0f..722685ec 100644 --- a/frontend/src/services/translationService.ts +++ b/frontend/src/services/translationService.ts @@ -17,7 +17,7 @@ export function getCachedTranslations(lang: string): Record | nu function saveCache(lang: string, data: Record): void { try { localStorage.setItem(getCacheKey(lang), JSON.stringify(data)); - } catch { /* localStorage full — ignore */ } + } catch { /* localStorage full - ignore */ } } /** Replace {{var}} placeholders with markers the translator won't touch */ From 67403d2e91dd00ac44513a2a28ae8f4a6a3b5435 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 11 Mar 2026 12:04:12 +0530 Subject: [PATCH 2/2] fix: update notifications controller spec to use userId, run npm audit fix --- backend/package-lock.json | 334 +++++++++--------- .../notifications.controller.spec.ts | 6 +- 2 files changed, 162 insertions(+), 178 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index 4100f8c7..cbe250b8 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -741,7 +741,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" @@ -754,7 +754,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -862,9 +862,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "dependencies": { @@ -1315,29 +1315,6 @@ } } }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" - } - }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -1754,13 +1731,13 @@ "license": "ISC" }, "node_modules/@jest/reporters/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -1934,7 +1911,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1955,7 +1932,7 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { @@ -2034,9 +2011,9 @@ } }, "node_modules/@nestjs/cli": { - "version": "11.0.14", - "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-11.0.14.tgz", - "integrity": "sha512-YwP03zb5VETTwelXU+AIzMVbEZKk/uxJL+z9pw0mdG9ogAtqZ6/mpmIM4nEq/NU8D0a7CBRLcMYUmWW/55pfqw==", + "version": "11.0.16", + "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-11.0.16.tgz", + "integrity": "sha512-P0H+Vcjki6P5160E5QnMt3Q0X5FTg4PZkP99Ig4lm/4JWqfw32j3EXv3YBTJ2DmxLwOQ/IS9F7dzKpMAgzKTGg==", "dev": true, "license": "MIT", "dependencies": { @@ -2056,7 +2033,7 @@ "tsconfig-paths": "4.2.0", "tsconfig-paths-webpack-plugin": "4.2.0", "typescript": "5.9.3", - "webpack": "5.103.0", + "webpack": "5.104.1", "webpack-node-externals": "3.0.0" }, "bin": { @@ -2111,14 +2088,14 @@ } }, "node_modules/@nestjs/config": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-4.0.2.tgz", - "integrity": "sha512-McMW6EXtpc8+CwTUwFdg6h7dYcBUpH5iUILCclAsa+MbCEvC9ZKu4dCHRlJqALuhjLw97pbQu62l4+wRwGeZqA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-4.0.3.tgz", + "integrity": "sha512-FQ3M3Ohqfl+nHAn5tp7++wUQw0f2nAk+SFKe8EpNRnIifPqvfJP6JQxPKtFLMOHbyer4X646prFG4zSRYEssQQ==", "license": "MIT", "dependencies": { - "dotenv": "16.4.7", - "dotenv-expand": "12.0.1", - "lodash": "4.17.21" + "dotenv": "17.2.3", + "dotenv-expand": "12.0.3", + "lodash": "4.17.23" }, "peerDependencies": { "@nestjs/common": "^10.0.0 || ^11.0.0", @@ -2211,15 +2188,15 @@ } }, "node_modules/@nestjs/platform-express": { - "version": "11.1.11", - "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.1.11.tgz", - "integrity": "sha512-kyABSskdMRIAMWL0SlbwtDy4yn59RL4HDdwHDz/fxWuv7/53YP8Y2DtV3/sHqY5Er0msMVTZrM38MjqXhYL7gw==", + "version": "11.1.16", + "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.1.16.tgz", + "integrity": "sha512-IOegr5+ZfUiMKgk+garsSU4MOkPRhm46e6w8Bp1GcO4vCdl9Piz6FlWAzKVfa/U3Hn/DdzSVJOW3TWcQQFdBDw==", "license": "MIT", "peer": true, "dependencies": { - "cors": "2.8.5", + "cors": "2.8.6", "express": "5.2.1", - "multer": "2.0.2", + "multer": "2.1.1", "path-to-regexp": "8.3.0", "tslib": "2.8.1" }, @@ -2340,15 +2317,15 @@ } }, "node_modules/@nestjs/swagger": { - "version": "11.2.5", - "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-11.2.5.tgz", - "integrity": "sha512-wCykbEybMqiYcvkyzPW4SbXKcwra9AGdajm0MvFgKR3W+gd1hfeKlo67g/s9QCRc/mqUU4KOE5Qtk7asMeFuiA==", + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-11.2.6.tgz", + "integrity": "sha512-oiXOxMQqDFyv1AKAqFzSo6JPvMEs4uA36Eyz/s2aloZLxUjcLfUMELSLSNQunr61xCPTpwEOShfmO7NIufKXdA==", "license": "MIT", "dependencies": { "@microsoft/tsdoc": "0.16.0", "@nestjs/mapped-types": "2.1.0", "js-yaml": "4.1.1", - "lodash": "4.17.21", + "lodash": "4.17.23", "path-to-regexp": "8.3.0", "swagger-ui-dist": "5.31.0" }, @@ -2630,28 +2607,28 @@ "version": "1.0.12", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tybys/wasm-util": { @@ -3923,13 +3900,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -4448,7 +4425,7 @@ "version": "8.16.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", - "dev": true, + "devOptional": true, "license": "MIT", "peer": true, "bin": { @@ -4485,7 +4462,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "acorn": "^8.11.0" @@ -4648,7 +4625,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/argparse": { @@ -5542,9 +5519,9 @@ "license": "MIT" }, "node_modules/cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", "license": "MIT", "dependencies": { "object-assign": "^4", @@ -5552,6 +5529,10 @@ }, "engines": { "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/cosmiconfig": { @@ -5585,7 +5566,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/cron": { @@ -5759,7 +5740,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -5802,9 +5783,9 @@ } }, "node_modules/dotenv": { - "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", "license": "BSD-2-Clause", "engines": { "node": ">=12" @@ -5814,9 +5795,9 @@ } }, "node_modules/dotenv-expand": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-12.0.1.tgz", - "integrity": "sha512-LaKRbou8gt0RNID/9RoI+J2rvXsBRPMV7p+ElHlPhcSARbCPDYcYG2s1TIzAfWv4YSgyY5taidWzzs31lNV3yQ==", + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-12.0.3.tgz", + "integrity": "sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA==", "license": "BSD-2-Clause", "dependencies": { "dotenv": "^16.4.5" @@ -5828,6 +5809,18 @@ "url": "https://dotenvx.com" } }, + "node_modules/dotenv-expand/node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -6027,9 +6020,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", "dev": true, "license": "MIT" }, @@ -6227,9 +6220,9 @@ } }, "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "dependencies": { @@ -7033,7 +7026,7 @@ "version": "3.9.0", "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 4" @@ -7156,17 +7149,40 @@ "dev": true, "license": "BSD-2-Clause" }, + "node_modules/glob/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/glob/node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" + "brace-expansion": "^5.0.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -7944,13 +7960,13 @@ "license": "ISC" }, "node_modules/jest-config/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -8311,13 +8327,13 @@ "license": "ISC" }, "node_modules/jest-runtime/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -8708,9 +8724,9 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "license": "MIT" }, "node_modules/lodash.includes": { @@ -8841,7 +8857,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/makeerror": { @@ -9000,9 +9016,9 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -9016,6 +9032,7 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9030,18 +9047,6 @@ "node": ">=16 || 14 >=14.17" } }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "license": "MIT", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -9049,21 +9054,22 @@ "license": "MIT" }, "node_modules/multer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz", - "integrity": "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-2.1.1.tgz", + "integrity": "sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==", "license": "MIT", "dependencies": { "append-field": "^1.0.0", "busboy": "^1.6.0", "concat-stream": "^2.0.0", - "mkdirp": "^0.5.6", - "object-assign": "^4.1.1", - "type-is": "^1.6.18", - "xtend": "^4.0.2" + "type-is": "^1.6.18" }, "engines": { "node": ">= 10.16.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/multer/node_modules/media-typer": { @@ -9884,9 +9890,9 @@ "license": "MIT" }, "node_modules/qs": { - "version": "6.14.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", - "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", + "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -9919,16 +9925,6 @@ ], "license": "MIT" }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -9992,7 +9988,7 @@ "version": "4.7.1", "resolved": "https://registry.npmjs.org/redis/-/redis-4.7.1.tgz", "integrity": "sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ==", - "dev": true, + "devOptional": true, "license": "MIT", "peer": true, "workspaces": [ @@ -10011,7 +10007,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" @@ -10021,7 +10017,7 @@ "version": "1.6.1", "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.1.tgz", "integrity": "sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw==", - "dev": true, + "devOptional": true, "license": "MIT", "peer": true, "dependencies": { @@ -10037,7 +10033,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.1.tgz", "integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" @@ -10047,7 +10043,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.7.tgz", "integrity": "sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" @@ -10057,7 +10053,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.2.0.tgz", "integrity": "sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" @@ -10067,7 +10063,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.1.0.tgz", "integrity": "sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==", - "dev": true, + "devOptional": true, "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" @@ -10077,7 +10073,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/reflect-metadata": { @@ -10306,9 +10302,9 @@ } }, "node_modules/schema-utils/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "peer": true, @@ -10378,16 +10374,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/serve-static": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", @@ -11019,16 +11005,15 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.16", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz", - "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==", + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.4.0.tgz", + "integrity": "sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", "schema-utils": "^4.3.0", - "serialize-javascript": "^6.0.2", "terser": "^5.31.1" }, "engines": { @@ -11368,7 +11353,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, + "devOptional": true, "license": "MIT", "peer": true, "dependencies": { @@ -11701,12 +11686,12 @@ "license": "ISC" }, "node_modules/typeorm/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -11735,7 +11720,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "peer": true, "bin": { @@ -12031,7 +12016,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/v8-to-istanbul": { @@ -12102,12 +12087,11 @@ } }, "node_modules/webpack": { - "version": "5.103.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.103.0.tgz", - "integrity": "sha512-HU1JOuV1OavsZ+mfigY0j8d1TgQgbZ6M+J75zDkpEAwYeXjWSqrGJtgnPblJjd/mAyTNQ7ygw0MiKOn6etz8yw==", + "version": "5.104.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.104.1.tgz", + "integrity": "sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -12117,10 +12101,10 @@ "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.15.0", "acorn-import-phases": "^1.0.3", - "browserslist": "^4.26.3", + "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.3", - "es-module-lexer": "^1.2.1", + "enhanced-resolve": "^5.17.4", + "es-module-lexer": "^2.0.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", @@ -12131,7 +12115,7 @@ "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", - "terser-webpack-plugin": "^5.3.11", + "terser-webpack-plugin": "^5.3.16", "watchpack": "^2.4.4", "webpack-sources": "^3.3.3" }, @@ -12424,7 +12408,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" diff --git a/backend/src/notifications/notifications.controller.spec.ts b/backend/src/notifications/notifications.controller.spec.ts index 1c7f92bf..1bdf4f20 100644 --- a/backend/src/notifications/notifications.controller.spec.ts +++ b/backend/src/notifications/notifications.controller.spec.ts @@ -36,7 +36,7 @@ describe('NotificationsController', () => { ]; mockNotificationsService.findByUser.mockResolvedValue(notifications); - const req = { user: { sub: 'user-123' } }; + const req = { user: { userId: 'user-123' } }; const result = await controller.getMyNotifications(req); expect(mockNotificationsService.findByUser).toHaveBeenCalledWith( @@ -50,7 +50,7 @@ describe('NotificationsController', () => { it('should mark a single notification as read', async () => { mockNotificationsService.markRead.mockResolvedValue(undefined); - const req = { user: { sub: 'user-123' } }; + const req = { user: { userId: 'user-123' } }; const result = await controller.markRead('n1', req); expect(mockNotificationsService.markRead).toHaveBeenCalledWith( @@ -65,7 +65,7 @@ describe('NotificationsController', () => { it('should mark all notifications as read', async () => { mockNotificationsService.markAllRead.mockResolvedValue(undefined); - const req = { user: { sub: 'user-123' } }; + const req = { user: { userId: 'user-123' } }; const result = await controller.markAllRead(req); expect(mockNotificationsService.markAllRead).toHaveBeenCalledWith(