fix(events): admin-set password on reset, full-URL gallery_link in all emails
Two related defects on the same gallery-email surface that PR #367 opened, addressed together: 1. Reset-password endpoint was a one-way auto-generate. `POST /admin/events/:id/reset-password` always called `generateReadablePassword()` and ignored any client-supplied value; the modal only offered a confirm + a forced auto-generated result. Admins who wanted to set a memorable customer-supplied password had no way to do it. Backend: route now reads optional `password` from the body. If present, validates with `validatePasswordInContext('gallery', …)` (same rules as create-event) and uses it; if absent, falls back to the existing generator, so old callers / cron stay functional. Switched the bcrypt rounds from a hard-coded `10` to `getBcryptRounds()` to match the create flow. Frontend: rebuilt `PasswordResetModal.tsx`. Typed input with show/hide, confirm-password field that appears on type, the same `<PasswordGenerator>` used by `CreateEventPage` (event-context- aware, fills both fields when used), send-email checkbox, client-side validation, server-side validation feedback inline. Submit empty → server auto-generates and the success screen shows the value with a copy button (legacy one-click flow preserved); submit with a typed password → success toast + close (no need to re-show what the admin already typed). Service layer: `events.service.resetPassword(id, sendEmail, password?)` only sends `password` in the body when set. Caller: `EventDetailsPage` now passes `eventDate` + `eventType` into the modal so the generator has event context. 2. `gallery_link` was the path-only `event.share_link` in three email-queue sites, so customer mail showed `/gallery/<slug>/<token>` instead of the full `https://example.com/gallery/<slug>/<token>` URL. - `adminEvents.js` reset-password queue (#1437) - `adminEvents.js` resend-creation-email queue (#1502) - `expirationChecker.js` expiration_warning queue (#82) All three now derive `shareUrl` from `buildShareLinkVariants` (the same helper already used by create-event, publish-from- draft, and event-rename). The other 4 callers (`adminEvents.js:651/913`, `events.js:187`, `eventRenameService.js:231`) already used the full URL — this closes the gap. Verified: TypeScript clean (`npx tsc --noEmit`), ESLint clean on every touched file (the 4 lint errors that remain in `adminEvents.js` are pre-existing and predate this branch).
This commit is contained in:
@@ -2,6 +2,7 @@ const cron = require('node-cron');
|
||||
const { db } = require('../database/db');
|
||||
const { archiveEvent } = require('./archiveService');
|
||||
const { queueEmail, getSupportEmail } = require('./emailProcessor');
|
||||
const { buildShareLinkVariants } = require('./shareLinkService');
|
||||
const logger = require('../utils/logger');
|
||||
const { formatBoolean } = require('../utils/dbCompat');
|
||||
|
||||
@@ -62,6 +63,9 @@ async function queueExpirationWarning(event) {
|
||||
|
||||
const recipientEmail = event.customer_email || event.host_email;
|
||||
const recipientName = event.customer_name || event.host_name || (recipientEmail ? recipientEmail.split('@')[0] : null);
|
||||
// event.share_link is the path-only form; use the full URL so the
|
||||
// recipient's mail client renders a clickable absolute link.
|
||||
const { shareUrl } = await buildShareLinkVariants({ slug: event.slug, shareToken: event.share_token });
|
||||
|
||||
// Date formatting + language detection happen inside processTemplate using
|
||||
// the recipient's resolved language — pass the raw ISO date and let the
|
||||
@@ -79,7 +83,7 @@ async function queueExpirationWarning(event) {
|
||||
event_date: event.event_date,
|
||||
days_remaining: daysRemaining.toString(),
|
||||
expiry_date: event.expires_at,
|
||||
gallery_link: event.share_link,
|
||||
gallery_link: shareUrl,
|
||||
gallery_password: '{{password_security_message}}'
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user