Ver código fonte

Fix blue-permit nonprofit flow, restyle email header, add real jurisdiction validation

- Blue AV Envelope: City of permit holder and Permit Number are now always
  collected for an own-organization permit, regardless of nonprofit status -
  a permit lookup using only the nonprofit authorization code doesn't work,
  so the code is now additional info when nonprofit status is Yes, not a
  replacement for city/permit number.
- Order confirmation email header simplified to "KCI Purple Envelope Order
  Confirmation" text, dropping the site's PE logo mark and tagline.
- Replaced the IsValidJurisdictionNumber stub (previously always returned
  true) with real validation against JurisdictionApiUrl, cached in
  Application scope (JurisdictionCacheMinutes, default 60) since the
  jurisdiction list is essentially static reference data. Falls back to
  stale cached data on a refresh failure rather than blocking order
  requests; fails open only when there's no cache at all.

  Hit two Classic ASP gotchas along the way: Scripting.Dictionary can't be
  stored in Application scope (ASP 0197, apartment-threaded COM object) -
  cached a delimited string instead - and the codebase's generic aspJSON
  parser took 43s to parse the ~1500-record API response, so switched to a
  targeted regex extraction of just the JCode field (~1s).
master
Daniel Covington 2 semanas atrás
pai
commit
a5b235beb5
4 arquivos alterados com 118 adições e 13 exclusões
  1. +8
    -7
      app/controllers/OrderApiController.asp
  2. +99
    -3
      app/models/JurisdictionValidator.asp
  3. +3
    -3
      app/views/Order/continue.asp
  4. +8
    -0
      public/web.config

+ 8
- 7
app/controllers/OrderApiController.asp Ver arquivo

@@ -146,9 +146,7 @@ Class OrderApiController_Class
"<table role=""presentation"" width=""100%"" cellpadding=""0"" cellspacing=""0"" style=""background:#faf7fd; padding:24px 0;""><tr><td align=""center"">" & _
"<table role=""presentation"" width=""600"" cellpadding=""0"" cellspacing=""0"" style=""background:#ffffff; border-radius:12px; overflow:hidden; box-shadow:0 4px 16px rgba(36,16,58,0.08);"">" & _
"<tr><td style=""background:#24103a; padding:24px 32px;"">" & _
"<span style=""display:inline-block; width:34px; height:34px; border-radius:50%; background:#7c3bc0; color:#fff; font-weight:800; font-size:12px; text-align:center; line-height:34px; vertical-align:middle;"">PE</span>" & _
"<span style=""color:#ffffff; font-weight:700; font-size:16px; margin-left:10px; vertical-align:middle;"">Purple Envelope</span>" & _
"<div style=""color:#dcc9ef; font-size:11px; margin-top:2px;"">Addressing &amp; Barcoding</div>" & _
"<span style=""color:#ffffff; font-weight:700; font-size:18px;"">KCI Purple Envelope Order Confirmation</span>" & _
"</td></tr>" & _
"<tr><td style=""padding:32px;"">" & _
"<div style=""color:#7c3bc0; font-weight:800; font-size:11px; letter-spacing:0.06em; text-transform:uppercase;"">Order Received</div>" & _
@@ -182,14 +180,17 @@ Class OrderApiController_Class
End If

If IsTrue(model.BlueWantsQuote) Then
' City/permit number are always collected for an own-organization permit - a
' permit lookup can't be done from the nonprofit authorization code alone, so
' that code is additional information when nonprofit status is Yes, not a
' replacement for city/permit number.
Dim bluePermitLine
bluePermitLine = ""
If LabelPermitOwnership(model.BluePermitOwnership) = "My organization's permit" Then
bluePermitLine = EmailRow("City of permit holder", model.BluePermitCity) & _
EmailRow("Permit number", model.BluePermitNumber)
If IsTrue(model.BlueHasNonprofitStatus) Then
bluePermitLine = EmailRow("Nonprofit authorization code", model.BlueNonprofitAuthCode)
Else
bluePermitLine = EmailRow("City of permit holder", model.BluePermitCity) & _
EmailRow("Permit number", model.BluePermitNumber)
bluePermitLine = bluePermitLine & EmailRow("Nonprofit authorization code", model.BlueNonprofitAuthCode)
End If
End If



+ 99
- 3
app/models/JurisdictionValidator.asp Ver arquivo

@@ -2,9 +2,105 @@
'=======================================================================================================================
' Jurisdiction Number Validation
'=======================================================================================================================
' STUB: always returns True. Replace with a real lookup once a jurisdictions
' table/reference list exists to validate the submitted number against.
' Validates a submitted jurisdiction number against the JCode field of the jurisdictions
' list served by JurisdictionApiUrl (see public/web.config). That list is essentially static
' reference data (townships/municipalities), so it's cached in Application scope for
' JurisdictionCacheMinutes (default 60) instead of being fetched on every /request-order
' submission. If a refresh attempt fails, stale cached data is used rather than blocking
' order requests; only when there is no cached data at all (e.g. immediately after an app
' pool restart, with the API also unreachable) does validation fail open (allow) rather than
' block every order request site-wide.
'
' The cache is stored as a single delimited STRING ("|code1|code2|...|"), not a
' Scripting.Dictionary or array of objects - Scripting.Dictionary is an apartment-threaded
' COM object, and IIS raises "ASP 0197: Disallowed object use" if you try to store one in
' the Application intrinsic (which is shared across all requests/threads). A plain string is
' just script data, so it's safe to cache this way.
'=======================================================================================================================

Function IsValidJurisdictionNumber(jurisdictionNumber)
IsValidJurisdictionNumber = True
Dim codesText
codesText = GetJurisdictionCodesText()

jurisdictionNumber = Trim(jurisdictionNumber)

If Len(codesText) = 0 Then
' No jurisdiction list available at all (first request after startup, API also
' down) - fail open rather than block every order request site-wide.
IsValidJurisdictionNumber = True
Else
IsValidJurisdictionNumber = (InStr(codesText, "|" & jurisdictionNumber & "|") > 0)
End If
End Function

' Returns the cached "|code1|code2|...|" string, refreshing it from JurisdictionApiUrl when
' missing or older than JurisdictionCacheMinutes. Falls back to the existing (stale) cached
' string if a refresh attempt fails.
Private Function GetJurisdictionCodesText()
Dim cacheMinutes, cachedAt, isStale

cacheMinutes = GetAppSetting("JurisdictionCacheMinutes")
If Not IsNumeric(cacheMinutes) Then cacheMinutes = 60

cachedAt = Application("JurisdictionCodesFetchedAt")
isStale = IsEmpty(cachedAt)
If Not isStale Then isStale = (DateDiff("n", cachedAt, Now()) >= CInt(cacheMinutes))

If isStale Then
Dim fresh
fresh = FetchJurisdictionCodesText()
If Len(fresh) > 0 Then
Application.Lock
Application("JurisdictionCodesText") = fresh
Application("JurisdictionCodesFetchedAt") = Now()
Application.Unlock
End If
End If

GetJurisdictionCodesText = Application("JurisdictionCodesText")
End Function

' Fetches the jurisdictions list and extracts every JCode value. Returns a
' "|code1|code2|...|" string, or "" on any failure (network, HTTP status, or no matches).
'
' Uses a targeted regex over the raw response text rather than this codebase's generic
' aspJSON parser (core/lib.json.asp) - that parser walks the input character-by-character in
' plain VBScript, which measured at over 40 seconds for this API's ~450KB/1500-record
' response. RegExp.Execute is implemented natively and handles the same payload
' near-instantly; since JCode is the only field this validator needs, a full generic parse
' isn't necessary anyway.
Private Function FetchJurisdictionCodesText()
Dim apiUrl : apiUrl = GetAppSetting("JurisdictionApiUrl")
Dim result : result = ""

On Error Resume Next

Dim http : Set http = Server.CreateObject("Msxml2.ServerXMLHTTP")
http.setTimeouts 5000, 5000, 5000, 5000
http.Open "GET", apiUrl, False
http.Send ""

If Err.Number = 0 And http.Status = 200 Then
Dim re, matches, m, codes, code
Set re = New RegExp
re.Pattern = """JCode""\s*:\s*""([^""]*)"""
re.Global = True
re.IgnoreCase = True

Set matches = re.Execute(http.responseText)
If Err.Number = 0 And matches.Count > 0 Then
codes = "|"
For Each m In matches
code = Trim(m.SubMatches(0))
If Len(code) > 0 Then codes = codes & code & "|"
Next
If Len(codes) > 1 Then result = codes
End If
End If

Err.Clear
On Error GoTo 0

FetchJurisdictionCodesText = result
End Function
%>

+ 3
- 3
app/views/Order/continue.asp Ver arquivo

@@ -217,13 +217,13 @@
},
{
type: "text", name: "BluePermitCity", title: "City of permit holder",
description: "Please provide the following information.",
visibleIf: "{BlueHasNonprofitStatus} = false",
description: "A permit lookup can't be done from the authorization code alone, so please also provide the following information.",
visibleIf: "{BluePermitOwnership} = 'OwnPermit'",
isRequired: true
},
{
type: "text", name: "BluePermitNumber", title: "Permit Number",
visibleIf: "{BlueHasNonprofitStatus} = false",
visibleIf: "{BluePermitOwnership} = 'OwnPermit'",
isRequired: true
}
]


+ 8
- 0
public/web.config Ver arquivo

@@ -53,6 +53,14 @@

<!-- Hours before an order continuation link (token) expires -->
<add key="OrderTokenExpirationHours" value="24" />

<!--
Jurisdiction number validation (request-order form). The list is essentially static
reference data, so it's cached in Application scope rather than fetched on every
submission - see JurisdictionCacheMinutes.
-->
<add key="JurisdictionApiUrl" value="http://192.168.1.40:8081/api/jurisdictions" />
<add key="JurisdictionCacheMinutes" value="60" />
</appSettings>

<system.webServer>


Carregando…
Cancelar
Salvar

Powered by TurnKey Linux.