From 7d440530b30533b1965c1f6fbb8a5bae8c941ac5 Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Sat, 31 Oct 2026 17:32:20 -0700 Subject: [PATCH] case 4762 - direct email to a user: messages say "User", not "Vendor" Co-Authored-By: Claude Opus 5.5 --- devdocs/modernization/NET10-PORT.md | 2 +- docs/8.0/ayanova/docs/changelog.md | 1 + server/AyaNova/Controllers/NotifyController.cs | 5 +++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/devdocs/modernization/NET10-PORT.md b/devdocs/modernization/NET10-PORT.md index 25509ef1..132462a6 100644 --- a/devdocs/modernization/NET10-PORT.md +++ b/devdocs/modernization/NET10-PORT.md @@ -252,7 +252,7 @@ FastMail password after the old Sockeye server is retired), John's cases. Found during the port, out of scope. One line each. -- `NotifyController.SendNotifySmtpDirectMessage`, User branch: the missing-address and inactive messages say "Vendor" instead of "User" (found in case 4723) +- **Fixed in case 4762.** `NotifyController.SendNotifySmtpDirectMessage`, User branch: the missing-address and inactive messages say "Vendor" instead of "User" (found in case 4723) - SMTP connection security mapping (`Mailer.cs`): "StartTls" connects with `useSsl: true`, which MailKit treats as TLS from the start (port 465), not STARTTLS (587); "None" uses STARTTLS when offered, which can be stripped. Correcting it could break customers using "StartTls" on port 465 (found in case 4724) - Integration test `DownloadNames` logs in again as the shared `Sales` user to get a download key, which replaces the token the other tests use for Sales while running in parallel (one session per user). Tests that need a download key should create their own user, as `TemplateExportRights` does (found in case 4727). Also fragile under parallel runs: `DataListOperations.WorkOrderList_PaginationOffsetAndLimitWork` fetches two pages of work orders and checks they do not overlap, while `WorkOrderCrud` creates and deletes work orders (failed once in case 4727) - From F6 (case 4726), split off as separate changes: a password strength rule (not empty is the only rule today; seeded trial users use their login as password) is a new, visible feature; `limit_req` on `/api/v8/auth` in the hosted nginx configuration belongs in the `sockeye-client` setup script and affects every hosted droplet. Both are second layers behind the login lockout diff --git a/docs/8.0/ayanova/docs/changelog.md b/docs/8.0/ayanova/docs/changelog.md index 2a585294..231e5620 100644 --- a/docs/8.0/ayanova/docs/changelog.md +++ b/docs/8.0/ayanova/docs/changelog.md @@ -23,6 +23,7 @@ IN PROGRESS - Backup: the [number of backups to keep](ops-form-backup.md#number-of-backups-to-keep) can no longer be set below 1; a setting of 0 already kept the most recent backup, the same as 1. - User interface: in some cases, when the web browser could not identify its time zone, dates and times were shown and entered in New York time; the browser's own offset from UTC is now used instead. A [time zone override](ay-start-localization.md#time-zone-override) in user options always takes precedence. - Email: report PDF files attached to customer notification emails now have the standard PDF content type; mail programs already opened them by their .pdf name. +- Email: sending an email directly to a user who has no email address, or who is inactive, now names them as a user instead of a vendor in the message. ### AyaNova 8.3.0 diff --git a/server/AyaNova/Controllers/NotifyController.cs b/server/AyaNova/Controllers/NotifyController.cs index 7cc06b99..5c455a62 100644 --- a/server/AyaNova/Controllers/NotifyController.cs +++ b/server/AyaNova/Controllers/NotifyController.cs @@ -339,10 +339,11 @@ namespace AyaNova.Api.Controllers bool isContact = o.UserType == UserType.Customer || o.UserType == UserType.HeadOffice; if (!Authorized.HasReadFullRole(HttpContext.Items, AyaType.User) && !(isContact && Authorized.HasReadFullRole(HttpContext.Items, AyaType.Customer))) return StatusCode(403, new ApiNotAuthorizedResponse()); + //case 4762: these said "Vendor" if (string.IsNullOrWhiteSpace(o.EmailAddress)) - return BadRequest(new ApiErrorResponse(ApiErrorCode.VALIDATION_MISSING_PROPERTY, "EmailAddress", $"Vendor {o.Name} doesn't have an email address no where to send this")); + return BadRequest(new ApiErrorResponse(ApiErrorCode.VALIDATION_MISSING_PROPERTY, "EmailAddress", $"User {o.Name} doesn't have an email address no where to send this")); if (o.Active == false) - return BadRequest(new ApiErrorResponse(ApiErrorCode.INVALID_OPERATION, "Active", $"Vendor {o.Name} is not active, only active Vendors can be emailed directly")); + return BadRequest(new ApiErrorResponse(ApiErrorCode.INVALID_OPERATION, "Active", $"User {o.Name} is not active, only active users can be emailed directly")); notifyDirectSMTP.ToAddress = o.EmailAddress; } break;