ASP Classic blog framework - BrainOrdure
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1054 line
33KB

  1. <%
  2. Function QuoteValue(val)
  3. if IsWrappedInSingleQuotes(val) then
  4. QuoteValue = val
  5. Exit Function
  6. end if
  7. Select Case VarType(val)
  8. Case vbString
  9. QuoteValue = "'" & Replace(val, "'", "''") & "'"
  10. Case vbDate
  11. if conn.Provider = "Microsoft.Jet.OLEDB.4.0" or conn.Provider = "Microsoft.ACE.OLEDB.12.0" then
  12. QuoteValue = "#" & FormatDateTime(val, 0) & "#"
  13. else
  14. ' SQL Server
  15. QuoteValue = "'" & FormatDateTime(val, 0) & "'"
  16. end if
  17. Case vbNull, vbEmpty
  18. QuoteValue = "Null"
  19. Case vbBoolean
  20. ' Return boolean values without quotes
  21. QuoteValue = "'" & CStr(val) & "'"
  22. Case Else
  23. If IsNumeric(val) Then
  24. QuoteValue = CLng(val)
  25. Else
  26. QuoteValue = CStr(val)
  27. End If
  28. End Select
  29. End Function
  30. Public Function GetAppSetting(key)
  31. Dim cacheKey, xml, nodes, node, i
  32. cacheKey = "AppSetting_" & key
  33. ' Check Application cache first for performance
  34. If Not IsEmpty(Application(cacheKey)) Then
  35. GetAppSetting = Application(cacheKey)
  36. Exit Function
  37. End If
  38. ' Load from web.config only if not cached
  39. Set xml = Server.CreateObject("Microsoft.XMLDOM")
  40. xml.Load(Server.MapPath("web.config"))
  41. Set nodes = xml.selectNodes("//appSettings/add")
  42. For i = 0 To nodes.Length - 1
  43. Set node = nodes.Item(i)
  44. If node.getAttribute("key") = key Then
  45. GetAppSetting = node.getAttribute("value")
  46. ' Cache the value for subsequent requests
  47. Application.Lock
  48. Application(cacheKey) = GetAppSetting
  49. Application.Unlock
  50. Exit Function
  51. End If
  52. Next
  53. GetAppSetting = "nothing"
  54. End Function
  55. Public Function GetEnvironmentValue(name)
  56. Dim shell, env, value, scopes, scope
  57. value = ""
  58. On Error Resume Next
  59. Set shell = Server.CreateObject("WScript.Shell")
  60. If Err.Number = 0 Then
  61. scopes = Array("PROCESS", "SYSTEM", "USER")
  62. For Each scope In scopes
  63. Set env = shell.Environment(scope)
  64. If Err.Number = 0 Then
  65. value = env(name)
  66. If Len(Trim(CStr(value))) > 0 Then Exit For
  67. End If
  68. Err.Clear
  69. Next
  70. Else
  71. Err.Clear
  72. End If
  73. On Error GoTo 0
  74. GetEnvironmentValue = Trim(CStr(value))
  75. End Function
  76. Public Function GetSecureSetting(key, envName)
  77. Dim value, envValue
  78. value = Trim(CStr(GetAppSetting(key)))
  79. If Len(value) > 0 And LCase(value) <> "nothing" Then
  80. GetSecureSetting = value
  81. Exit Function
  82. End If
  83. envValue = Trim(CStr(GetEnvironmentValue(envName)))
  84. If Len(envValue) > 0 Then
  85. On Error Resume Next
  86. UpdateAppSetting key, envValue
  87. Err.Clear
  88. On Error GoTo 0
  89. GetSecureSetting = envValue
  90. Exit Function
  91. End If
  92. GetSecureSetting = ""
  93. End Function
  94. Public Function GetGenerationPromptTemplate()
  95. Dim prompt
  96. prompt = Trim(CStr(GetAppSetting("AbacusGenerationPrompt")))
  97. If Len(prompt) = 0 Or LCase(prompt) = "nothing" Then
  98. prompt = "You write clear, engaging blog post content for a classic ASP blog. Return only valid JSON with two keys: summary and body. Summary must be 1 to 2 sentences. Body must be 3 to 5 short paragraphs separated by blank lines. Do not use markdown fences, bullets, or code blocks." & vbCrLf & vbCrLf & _
  99. "Create blog content for this post title: {TITLE}" & vbCrLf & _
  100. "Existing summary: {SUMMARY}" & vbCrLf & _
  101. "Existing body: {BODY}" & vbCrLf & _
  102. "Keep the title unchanged. Make the content readable and helpful for a general audience." & vbCrLf & _
  103. "Also include an image_prompt field in the generated JSON output that describes a magazine-style feature image."
  104. End If
  105. GetGenerationPromptTemplate = prompt
  106. End Function
  107. Public Function BuildGenerationPrompt(ByRef post)
  108. Dim template
  109. template = GetGenerationPromptTemplate()
  110. template = Replace(template, "{TITLE}", SafePromptText(post.Title))
  111. template = Replace(template, "{SUMMARY}", SafePromptText(post.Summary))
  112. template = Replace(template, "{BODY}", SafePromptText(post.Body))
  113. BuildGenerationPrompt = template
  114. End Function
  115. Public Function SafePromptText(ByVal value)
  116. If IsNull(value) Or IsEmpty(value) Then
  117. SafePromptText = ""
  118. Else
  119. SafePromptText = CStr(value)
  120. End If
  121. End Function
  122. Public Function UpdateAppSetting(key, value)
  123. Dim xml, nodes, node, appSettings, found
  124. Set xml = Server.CreateObject("Microsoft.XMLDOM")
  125. xml.async = False
  126. xml.preserveWhiteSpace = True
  127. xml.Load Server.MapPath("web.config")
  128. If xml.parseError.errorCode <> 0 Then
  129. Err.Raise 1, "UpdateAppSetting", "Unable to load web.config: " & xml.parseError.reason
  130. End If
  131. Set nodes = xml.selectNodes("//appSettings/add[@key='" & key & "']")
  132. found = False
  133. If Not (nodes Is Nothing) Then
  134. If nodes.Length > 0 Then
  135. Set node = nodes.Item(0)
  136. node.setAttribute "value", value
  137. found = True
  138. End If
  139. End If
  140. If Not found Then
  141. Set appSettings = xml.selectSingleNode("//appSettings")
  142. If appSettings Is Nothing Then
  143. Err.Raise 1, "UpdateAppSetting", "<appSettings> section not found in web.config."
  144. End If
  145. Set node = xml.createElement("add")
  146. node.setAttribute "key", key
  147. node.setAttribute "value", value
  148. appSettings.appendChild node
  149. End If
  150. xml.Save Server.MapPath("web.config")
  151. Application.Contents.Remove("AppSetting_" & key)
  152. UpdateAppSetting = True
  153. End Function
  154. Public Sub ShowServerVariables
  155. Dim varName, htmlTable
  156. htmlTable = "<table border='1' cellspacing='0' cellpadding='5'>"
  157. htmlTable = htmlTable & "<thead><tr><th>Variable Name</th><th>Value</th></tr></thead><tbody>"
  158. ' Loop through all server variables
  159. For Each varName In Request.ServerVariables
  160. htmlTable = htmlTable & "<tr>"
  161. htmlTable = htmlTable & "<td>" & Server.HTMLEncode(varName) & "</td>"
  162. htmlTable = htmlTable & "<td>" & Server.HTMLEncode(Request.ServerVariables(varName)) & "</td>"
  163. htmlTable = htmlTable & "</tr>"
  164. Next
  165. htmlTable = htmlTable & "</tbody></table>"
  166. ' Output the HTML table
  167. Response.Write(htmlTable)
  168. End Sub
  169. '------------------------------------------------------------------------------
  170. ' Utility: IIf Function for VBScript
  171. ' Usage: result = IIf(condition, trueValue, falseValue)
  172. '------------------------------------------------------------------------------
  173. Function IIf(condition, trueValue, falseValue)
  174. On Error Resume Next
  175. If CBool(condition) Then
  176. IIf = trueValue
  177. Else
  178. IIf = falseValue
  179. End If
  180. If Err.Number <> 0 Then
  181. ' Optional: handle or log error in conversion/evaluation
  182. Err.Clear
  183. End If
  184. On Error GoTo 0
  185. End Function
  186. '-----------------------------
  187. ' Utility: Generic Error Reporter
  188. '-----------------------------
  189. Public Sub ErrorCheck(context)
  190. If Err.Number <> 0 Then
  191. Dim errHtml
  192. errHtml = "<div style='padding:10px; border:2px solid red; background:#fdd; font-family:Verdana; font-size:12px;'>"
  193. errHtml = errHtml & "<strong>Error occurred" & IIf(Not IsEmpty(context) And context <> "", ": " & context, "") & "</strong><br />"
  194. errHtml = errHtml & "<em>Time:</em> " & Now() & "<br />"
  195. errHtml = errHtml & "<em>Number:</em> " & Err.Number & "<br />"
  196. errHtml = errHtml & "<em>Description:</em> " & Server.HTMLEncode(Err.Description) & "<br />"
  197. If Len(Err.Source) > 0 Then
  198. errHtml = errHtml & "<em>Source:</em> " & Server.HTMLEncode(Err.Source) & "<br />"
  199. End If
  200. errHtml = errHtml & "</div>"
  201. Response.Write errHtml
  202. Err.Clear
  203. End If
  204. End Sub
  205. '------------------------------------------------------------------------------
  206. ' Utility: TrimQueryParams
  207. ' Removes everything from the first "?" or "&" onward.
  208. ' Usage:
  209. ' CleanPath = TrimQueryParams(rawPath)
  210. '------------------------------------------------------------------------------
  211. Function TrimQueryParams(rawPath)
  212. Dim posQ, posA, cutPos
  213. ' find the first occurrences of "?" and "&"
  214. posQ = InStr(rawPath, "?")
  215. posA = InStr(rawPath, "&")
  216. ' determine the earliest cut position (>0)
  217. If posQ > 0 And posA > 0 Then
  218. cutPos = IIf(posQ < posA, posQ, posA)
  219. ElseIf posQ > 0 Then
  220. cutPos = posQ
  221. ElseIf posA > 0 Then
  222. cutPos = posA
  223. Else
  224. cutPos = 0
  225. End If
  226. ' if found, return up to just before that char
  227. If cutPos > 0 Then
  228. TrimQueryParams = Left(rawPath, cutPos - 1)
  229. Else
  230. TrimQueryParams = rawPath
  231. End If
  232. End Function
  233. Function DecodeUrlPath(ByVal rawPath)
  234. Dim current, previous
  235. current = Trim(CStr(rawPath))
  236. On Error Resume Next
  237. Do
  238. previous = current
  239. current = Server.URLDecode(current)
  240. If Err.Number <> 0 Then
  241. Err.Clear
  242. current = previous
  243. Exit Do
  244. End If
  245. Loop While current <> previous
  246. On Error GoTo 0
  247. current = Replace(current, "%252D", "-")
  248. current = Replace(current, "%252d", "-")
  249. current = Replace(current, "%2D", "-")
  250. current = Replace(current, "%2d", "-")
  251. current = Replace(current, "%25", "%")
  252. DecodeUrlPath = current
  253. End Function
  254. Sub Destroy(o)
  255. if isobject(o) then
  256. if not o is nothing then
  257. on error resume next
  258. o.close
  259. on error goto 0
  260. set o = nothing
  261. end if
  262. end if
  263. End Sub
  264. 'prepends indents
  265. Private Sub puti(v)
  266. put Spaces(m_indent) & v
  267. End Sub
  268. Sub put(v)
  269. Select Case typename(v)
  270. Case "LinkedList_Class" : response.write join(v.TO_Array, ", ")
  271. Case "DynamicArray_Class" : response.write JoinList(v)
  272. Case "Variant()" : response.write join(v, ", ")
  273. Case else : response.write v
  274. End Select
  275. End Sub
  276. Sub put_
  277. put "<br>"
  278. End Sub
  279. Sub putl(v)
  280. put v
  281. put_
  282. End Sub
  283. '---------------------------------------------------------------------------------------------------------------------
  284. 'Wrapper for Server.HTMLEncode() -- makes it easier on the eyes when reading the HTML code
  285. Function H(s)
  286. If Not IsEmpty(s) and Not IsNull(s) then
  287. H = Server.HTMLEncode(s)
  288. Else
  289. H = ""
  290. End If
  291. End Function
  292. Function RenderPostBody(ByVal body)
  293. Dim raw
  294. If IsNull(body) Or IsEmpty(body) Then
  295. RenderPostBody = ""
  296. Exit Function
  297. End If
  298. raw = CStr(body)
  299. If IsHtmlPostBody(raw) Then
  300. RenderPostBody = raw
  301. Else
  302. raw = Server.HTMLEncode(raw)
  303. raw = Replace(raw, vbCrLf, "<br>")
  304. raw = Replace(raw, vbCr, "<br>")
  305. raw = Replace(raw, vbLf, "<br>")
  306. RenderPostBody = raw
  307. End If
  308. End Function
  309. Function IsHtmlPostBody(ByVal text)
  310. Dim lowerText
  311. lowerText = LCase(CStr(text))
  312. IsHtmlPostBody = _
  313. (InStr(lowerText, "<p") > 0) Or _
  314. (InStr(lowerText, "<div") > 0) Or _
  315. (InStr(lowerText, "<br") > 0) Or _
  316. (InStr(lowerText, "<strong") > 0) Or _
  317. (InStr(lowerText, "<em") > 0) Or _
  318. (InStr(lowerText, "<ul") > 0) Or _
  319. (InStr(lowerText, "<ol") > 0) Or _
  320. (InStr(lowerText, "<li") > 0) Or _
  321. (InStr(lowerText, "<a ") > 0) Or _
  322. (InStr(lowerText, "<img") > 0) Or _
  323. (InStr(lowerText, "<blockquote") > 0) Or _
  324. (InStr(lowerText, "<h1") > 0) Or _
  325. (InStr(lowerText, "<h2") > 0) Or _
  326. (InStr(lowerText, "<h3") > 0) Or _
  327. (InStr(lowerText, "<h4") > 0) Or _
  328. (InStr(lowerText, "<h5") > 0) Or _
  329. (InStr(lowerText, "<h6") > 0) Or _
  330. (InStr(lowerText, "<code") > 0) Or _
  331. (InStr(lowerText, "<pre") > 0)
  332. End Function
  333. Function ExtractFirstImageSrc(ByVal html)
  334. Dim text, imgPos, srcPos, quoteChar, startPos, endPos, fallbackEnd
  335. If IsNull(html) Or IsEmpty(html) Then
  336. ExtractFirstImageSrc = ""
  337. Exit Function
  338. End If
  339. text = CStr(html)
  340. imgPos = InStr(1, text, "<img", vbTextCompare)
  341. If imgPos = 0 Then
  342. ExtractFirstImageSrc = ""
  343. Exit Function
  344. End If
  345. srcPos = InStr(imgPos, text, "src=", vbTextCompare)
  346. If srcPos = 0 Then
  347. ExtractFirstImageSrc = ""
  348. Exit Function
  349. End If
  350. quoteChar = Mid(text, srcPos + 4, 1)
  351. If quoteChar = """" Or quoteChar = "'" Then
  352. startPos = srcPos + 5
  353. endPos = InStr(startPos, text, quoteChar)
  354. If endPos > startPos Then
  355. ExtractFirstImageSrc = Mid(text, startPos, endPos - startPos)
  356. Exit Function
  357. End If
  358. End If
  359. startPos = srcPos + 4
  360. fallbackEnd = InStr(startPos, text, " ")
  361. If fallbackEnd = 0 Then fallbackEnd = InStr(startPos, text, ">")
  362. If fallbackEnd > startPos Then
  363. ExtractFirstImageSrc = Mid(text, startPos, fallbackEnd - startPos)
  364. Else
  365. ExtractFirstImageSrc = ""
  366. End If
  367. End Function
  368. Function AiImageUrl(ByVal prompt)
  369. AiImageUrl = "/ai-image?prompt=" & Server.URLEncode(Trim(CStr(prompt)))
  370. End Function
  371. Function GetAiImageProvider()
  372. Dim provider
  373. provider = LCase(Trim(CStr(GetAppSetting("AiImageProvider"))))
  374. If Len(provider) = 0 Or provider = "nothing" Then
  375. provider = "pollinations"
  376. End If
  377. GetAiImageProvider = provider
  378. End Function
  379. Function GetAiImageRemoteBaseUrl()
  380. Dim provider, baseUrl
  381. provider = GetAiImageProvider()
  382. If provider = "abacus" Then
  383. baseUrl = Trim(CStr(GetAppSetting("AbacusImageBaseUrl")))
  384. If Len(baseUrl) = 0 Or LCase(baseUrl) = "nothing" Then
  385. baseUrl = Trim(CStr(GetAppSetting("AiImageBaseUrl")))
  386. End If
  387. Else
  388. baseUrl = Trim(CStr(GetAppSetting("AiImageBaseUrl")))
  389. End If
  390. If Len(baseUrl) = 0 Or LCase(baseUrl) = "nothing" Then
  391. baseUrl = "https://image.pollinations.ai/prompt/"
  392. End If
  393. If Right(baseUrl, 1) <> "/" Then baseUrl = baseUrl & "/"
  394. GetAiImageRemoteBaseUrl = baseUrl
  395. End Function
  396. Function GetAiImageRemoteUrl(ByVal prompt)
  397. Dim cleanPrompt
  398. cleanPrompt = Trim(CStr(prompt))
  399. If Len(cleanPrompt) = 0 Then
  400. GetAiImageRemoteUrl = ""
  401. Else
  402. GetAiImageRemoteUrl = GetAiImageRemoteBaseUrl() & Server.URLEncode(cleanPrompt)
  403. End If
  404. End Function
  405. '------------------------------------------------------------------------------
  406. ' Canonical application URL helpers
  407. ' - Categories use numeric IDs
  408. ' - Posts use slug permalinks for public links and numeric IDs for admin actions
  409. '------------------------------------------------------------------------------
  410. Function CategoryUrl(ByVal categoryId)
  411. CategoryUrl = "/categories/" & Server.URLEncode(CStr(categoryId))
  412. End Function
  413. Function CategoriesUrl()
  414. CategoriesUrl = "/categories"
  415. End Function
  416. Function CategoryNewUrl()
  417. CategoryNewUrl = "/categories/new"
  418. End Function
  419. Function CategoryEditUrl(ByVal categoryId)
  420. CategoryEditUrl = CategoryUrl(categoryId) & "/edit"
  421. End Function
  422. Function CategoryDeleteUrl(ByVal categoryId)
  423. CategoryDeleteUrl = CategoryUrl(categoryId) & "/delete"
  424. End Function
  425. Function PostUrl(ByVal slug)
  426. PostUrl = "/posts/" & NormalizeSlug(slug)
  427. End Function
  428. Function PostPath(ByVal slug)
  429. PostPath = "/posts/" & NormalizeSlug(slug)
  430. End Function
  431. Function PostsUrl()
  432. PostsUrl = "/posts"
  433. End Function
  434. Function PostNewUrl()
  435. PostNewUrl = "/posts/new"
  436. End Function
  437. Function PostEditUrl(ByVal postId)
  438. PostEditUrl = "/posts/" & Server.URLEncode(CStr(postId)) & "/edit"
  439. End Function
  440. Function PostUpdateUrl(ByVal postId)
  441. PostUpdateUrl = "/posts/" & Server.URLEncode(CStr(postId))
  442. End Function
  443. Function PostDeleteUrl(ByVal postId)
  444. PostDeleteUrl = "/posts/" & Server.URLEncode(CStr(postId)) & "/delete"
  445. End Function
  446. Function AdminPostPublishUrl(ByVal postId)
  447. AdminPostPublishUrl = "/admin/posts/" & Server.URLEncode(CStr(postId)) & "/publish"
  448. End Function
  449. Function AdminPostUnpublishUrl(ByVal postId)
  450. AdminPostUnpublishUrl = "/admin/posts/" & Server.URLEncode(CStr(postId)) & "/unpublish"
  451. End Function
  452. Function AdminPostAIUrl(ByVal postId)
  453. AdminPostAIUrl = "/admin/posts/" & Server.URLEncode(CStr(postId)) & "/ai"
  454. End Function
  455. Function AdminCommentsUrl()
  456. AdminCommentsUrl = "/admin/comments"
  457. End Function
  458. Function AdminCommentApproveUrl(ByVal commentId)
  459. AdminCommentApproveUrl = "/admin/comments/" & Server.URLEncode(CStr(commentId)) & "/approve"
  460. End Function
  461. Function AdminCommentUnapproveUrl(ByVal commentId)
  462. AdminCommentUnapproveUrl = "/admin/comments/" & Server.URLEncode(CStr(commentId)) & "/unapprove"
  463. End Function
  464. Function AdminCommentDeleteUrl(ByVal commentId)
  465. AdminCommentDeleteUrl = "/admin/comments/" & Server.URLEncode(CStr(commentId)) & "/delete"
  466. End Function
  467. Function AdminAIPromptUrl()
  468. AdminAIPromptUrl = "/admin/ai-prompt"
  469. End Function
  470. Function AdminAIPromptUpdateUrl()
  471. AdminAIPromptUpdateUrl = "/admin/ai-prompt"
  472. End Function
  473. Function AdminUrl()
  474. AdminUrl = "/admin"
  475. End Function
  476. Function CommentsUrl()
  477. CommentsUrl = "/comments"
  478. End Function
  479. Function NormalizeSlug(ByVal slug)
  480. Dim current, previous
  481. current = Trim(CStr(slug))
  482. If Len(current) = 0 Then
  483. NormalizeSlug = ""
  484. Exit Function
  485. End If
  486. On Error Resume Next
  487. Do
  488. previous = current
  489. current = Server.URLDecode(current)
  490. If Err.Number <> 0 Then
  491. Err.Clear
  492. current = previous
  493. Exit Do
  494. End If
  495. Loop While current <> previous
  496. On Error GoTo 0
  497. current = Replace(current, "%252D", "-")
  498. current = Replace(current, "%252d", "-")
  499. current = Replace(current, "%2D", "-")
  500. current = Replace(current, "%2d", "-")
  501. current = Replace(current, "%25", "%")
  502. NormalizeSlug = current
  503. End Function
  504. Function EstimateReadTime(ByVal body)
  505. Dim text, re, words, count, minutes
  506. text = ""
  507. If Not (IsNull(body) Or IsEmpty(body)) Then
  508. text = CStr(body)
  509. End If
  510. On Error Resume Next
  511. Set re = Server.CreateObject("VBScript.RegExp")
  512. If Err.Number = 0 Then
  513. re.Global = True
  514. re.IgnoreCase = True
  515. re.Pattern = "<[^>]+>"
  516. text = re.Replace(text, " ")
  517. re.Pattern = "&[a-z0-9#]+;"
  518. text = re.Replace(text, " ")
  519. re.Pattern = "\s+"
  520. text = Trim(re.Replace(text, " "))
  521. Else
  522. Err.Clear
  523. text = Replace(text, vbCrLf, " ")
  524. text = Replace(text, vbCr, " ")
  525. text = Replace(text, vbLf, " ")
  526. End If
  527. On Error GoTo 0
  528. If Len(text) = 0 Then
  529. EstimateReadTime = "1 min read"
  530. Exit Function
  531. End If
  532. words = Split(text, " ")
  533. count = UBound(words) + 1
  534. minutes = CLng((count + 149) / 150)
  535. If minutes < 1 Then minutes = 1
  536. EstimateReadTime = CStr(minutes) & " min read"
  537. End Function
  538. '=======================================================================================================================
  539. ' Adapted from Tolerable library
  540. '=======================================================================================================================
  541. ' This subroutine allows us to ignore the difference
  542. ' between object and primitive assignments. This is
  543. ' essential for many parts of the engine.
  544. Public Sub Assign(ByRef var, ByVal val)
  545. If IsObject(val) Then
  546. Set var = val
  547. Else
  548. var = val
  549. End If
  550. End Sub
  551. ' This is similar to the ? : operator of other languages.
  552. ' Unfortunately, both the if_true and if_false "branches"
  553. ' will be evalauted before the condition is even checked. So,
  554. ' you'll only want to use this for simple expressions.
  555. Public Function Choice(ByVal cond, ByVal if_true, ByVal if_false)
  556. If cond Then
  557. Assign Choice, if_true
  558. Else
  559. Assign Choice, if_false
  560. End If
  561. End Function
  562. ' Allows single-quotes to be used in place of double-quotes.
  563. ' Basically, this is a cheap trick that can make it easier
  564. ' to specify Lambdas.
  565. Public Function Q(ByVal input)
  566. Q = Replace(input, "'", """")
  567. End Function
  568. Function SurroundString(inputVar)
  569. If VarType(inputVar) = vbString Then
  570. SurroundString = """" & inputVar & """"
  571. Else
  572. SurroundString = inputVar
  573. End If
  574. End Function
  575. Function SurroundStringInArray(arr)
  576. Dim i
  577. For i = LBound(arr) To UBound(arr)
  578. If IsString(arr(i)) Then
  579. arr(i) = """" & arr(i) & """"
  580. End If
  581. Next
  582. SurroundStringInArray = arr
  583. End Function
  584. '-----------------------------------------------------------------------------------------------------------------------
  585. 'Boolean type checkers
  586. 'Don't forget IsArray is built-in!
  587. Function IsString(value)
  588. IsString = Choice(typename(value) = "String", true, false)
  589. End Function
  590. Function IsDict(value)
  591. IsDict = Choice(typename(value) = "Dictionary", true, false)
  592. End Function
  593. Function IsRecordset(value)
  594. IsRecordset = Choice(typename(value) = "Recordset", true, false)
  595. End Function
  596. Function IsLinkedList(value)
  597. IsLinkedList = Choice(typename(value) = "LinkedList_Class", true, false)
  598. End Function
  599. Function IsArray(value)
  600. IsArray = Choice(typename(value) = "Variant()", true, false)
  601. End Function
  602. '--------------------------------------------------------------------
  603. ' Returns True when the named key is present in Session.Contents
  604. ' • Handles scalars (String, Integer, etc.), objects, Empty, and Null
  605. '--------------------------------------------------------------------
  606. Function SessionHasKey(keyName)
  607. 'Loop over the existing keys—Session.Contents is like a dictionary
  608. Dim k
  609. For Each k In Session.Contents
  610. If StrComp(k, keyName, vbTextCompare) = 0 Then
  611. SessionHasKey = True
  612. Exit Function
  613. End If
  614. Next
  615. SessionHasKey = False 'not found
  616. End Function
  617. Function RenderObjectsAsTable(arr,boolUseTabulator)
  618. Dim html, propNames, i, j, obj, val, pkName, isPk
  619. If IsEmpty(arr) Or Not IsArray(arr) Then
  620. RenderObjectsAsTable = "<!-- no data -->"
  621. Exit Function
  622. End If
  623. Set obj = arr(0)
  624. On Error Resume Next
  625. propNames = obj.Properties
  626. pkName = obj.PrimaryKey
  627. On Error GoTo 0
  628. If IsEmpty(propNames) Or Len(pkName) = 0 Then
  629. RenderObjectsAsTable = "<!-- missing properties or primary key -->"
  630. Exit Function
  631. End If
  632. html = "<div class='table-wrapper'>" & vbCrLf
  633. html = html & "<table class='pobo-table' id='pobo-table'>" & vbCrLf
  634. html = html & " <thead><tr>" & vbCrLf
  635. For i = 0 To UBound(propNames)
  636. html = html & " <th>" & Server.HTMLEncode(propNames(i)) & "</th>" & vbCrLf
  637. Next
  638. html = html & " </tr></thead>" & vbCrLf
  639. html = html & " <tbody>" & vbCrLf
  640. For j = 0 To UBound(arr)
  641. Set obj = arr(j)
  642. html = html & " <tr>" & vbCrLf
  643. For i = 0 To UBound(propNames)
  644. val = GetDynamicProperty(obj, propNames(i))
  645. isPk = (StrComp(propNames(i), pkName, vbTextCompare) = 0)
  646. If IsNull(val) Or IsEmpty(val) Then
  647. val = "&nbsp;"
  648. ElseIf IsDate(val) Then
  649. val = FormatDateTime(val, vbShortDate)
  650. ElseIf VarType(val) = vbBoolean Then
  651. val = IIf(val, "True", "False")
  652. Else
  653. val = CStr(val)
  654. Dim maxLen : maxLen = CInt(GetAppSetting("TableCellMaxLength"))
  655. If maxLen <= 0 Then maxLen = 90
  656. If Len(val) > maxLen Then
  657. val = Left(val, maxLen - 3) & "..."
  658. End If
  659. val = Server.HTMLEncode(val)
  660. End If
  661. If isPk and boolUseTabulator = False Then
  662. val = "<a href=""" & obj.Tablename & "/edit/" & GetDynamicProperty(obj, pkName) & """ class=""table-link"">" & val & "</a>"
  663. End If
  664. html = html & " <td>" & val & "</td>" & vbCrLf
  665. Next
  666. html = html & " </tr>" & vbCrLf
  667. Next
  668. html = html & " </tbody>" & vbCrLf & "</table>" & vbCrLf & "</div>"
  669. RenderObjectsAsTable = html
  670. End Function
  671. Function RenderFormFromObject(obj)
  672. Dim html, propNames, i, name, val, inputType
  673. Dim pkName, tableName, checkedAttr
  674. On Error Resume Next
  675. propNames = obj.Properties
  676. pkName = obj.PrimaryKey
  677. tableName = obj.TableName
  678. On Error GoTo 0
  679. If IsEmpty(propNames) Or Len(pkName) = 0 Then
  680. RenderFormFromObject = "<!-- Invalid object -->"
  681. Exit Function
  682. End If
  683. html = "<form method='post' action='/" & tableName & "/save' class='article-content'>" & vbCrLf
  684. For i = 0 To UBound(propNames)
  685. name = propNames(i)
  686. val = GetDynamicProperty(obj, name)
  687. ' Handle nulls
  688. If IsNull(val) Then val = ""
  689. ' Primary key → hidden input
  690. If StrComp(name, pkName, vbTextCompare) = 0 Then
  691. html = html & " <input type='hidden' name='" & name & "' value='" & Server.HTMLEncode(val) & "' />" & vbCrLf
  692. 'Continue For
  693. End If
  694. html = html & " <div class='form-group'>" & vbCrLf
  695. html = html & " <label for='" & name & "'>" & name & "</label>" & vbCrLf
  696. Select Case True
  697. Case VarType(val) = vbBoolean
  698. checkedAttr = ""
  699. If val = True Then checkedAttr = " checked"
  700. html = html & " <input type='checkbox' class='form-check-input' name='" & name & "' id='" & name & "' value='true'" & checkedAttr & " />" & vbCrLf
  701. Case IsDate(val)
  702. html = html & " <input type='date' class='form-control' name='" & name & "' id='" & name & "' value='" & FormatDateForInput(val) & "' />" & vbCrLf
  703. Case IsNumeric(val)
  704. html = html & " <input type='number' class='form-control' name='" & name & "' id='" & name & "' value='" & val & "' />" & vbCrLf
  705. Case Len(val) > CInt(GetAppSetting("FormTextareaThreshold"))
  706. html = html & " <textarea class='form-control' name='" & name & "' id='" & name & "' rows='6'>" & Server.HTMLEncode(val) & "</textarea>" & vbCrLf
  707. Case Else
  708. html = html & " <input type='text' class='form-control' name='" & name & "' id='" & name & "' value='" & Server.HTMLEncode(val) & "' />" & vbCrLf
  709. End Select
  710. html = html & " </div>" & vbCrLf
  711. Next
  712. html = html & " <button type='submit' class='btn btn-primary btn-lg'>Save</button>" & vbCrLf
  713. html = html & "</form>" & vbCrLf
  714. RenderFormFromObject = html
  715. End Function
  716. Function GetDynamicProperty(obj, propName)
  717. On Error Resume Next
  718. Dim result
  719. Execute "result = obj." & propName
  720. If Err.Number <> 0 Then
  721. result = ""
  722. Err.Clear
  723. End If
  724. GetDynamicProperty = result
  725. On Error GoTo 0
  726. End Function
  727. Function FormatDateForInput(val)
  728. If IsDate(val) Then
  729. Dim yyyy, mm, dd
  730. yyyy = Year(val)
  731. mm = Right("0" & Month(val), 2)
  732. dd = Right("0" & Day(val), 2)
  733. FormatDateForInput = yyyy & "-" & mm & "-" & dd
  734. Else
  735. FormatDateForInput = ""
  736. End If
  737. End Function
  738. '-------------------------------------------------------------
  739. ' Returns obj.<propName> for any public VBScript class property
  740. '-------------------------------------------------------------
  741. Function GetObjProp(o, pName)
  742. Dim tmp
  743. ' Build a tiny statement like: tmp = o.UserID
  744. Execute "tmp = o." & pName
  745. GetObjProp = tmp
  746. End Function
  747. Function GenerateSlug(title)
  748. Dim slug
  749. slug = LCase(title) ' Convert to lowercase
  750. slug = Replace(slug, "&", "and") ' Replace ampersands
  751. slug = Replace(slug, "'", "") ' Remove apostrophes
  752. slug = Replace(slug, """", "") ' Remove quotes
  753. slug = Replace(slug, "–", "-") ' Replace en dash
  754. slug = Replace(slug, "—", "-") ' Replace em dash
  755. slug = Replace(slug, "/", "-") ' Replace slashes
  756. slug = Replace(slug, "\", "-") ' Replace backslashes
  757. ' Remove all non-alphanumeric and non-hyphen/space characters
  758. Dim i, ch, clean
  759. clean = ""
  760. For i = 1 To Len(slug)
  761. ch = Mid(slug, i, 1)
  762. If (ch >= "a" And ch <= "z") Or (ch >= "0" And ch <= "9") Or ch = " " Or ch = "-" Then
  763. clean = clean & ch
  764. End If
  765. Next
  766. ' Replace multiple spaces or hyphens with single hyphen
  767. Do While InStr(clean, " ") > 0
  768. clean = Replace(clean, " ", " ")
  769. Loop
  770. clean = Replace(clean, " ", "-")
  771. Do While InStr(clean, "--") > 0
  772. clean = Replace(clean, "--", "-")
  773. Loop
  774. ' Trim leading/trailing hyphens
  775. Do While Left(clean, 1) = "-"
  776. clean = Mid(clean, 2)
  777. Loop
  778. Do While Right(clean, 1) = "-"
  779. clean = Left(clean, Len(clean) - 1)
  780. Loop
  781. GenerateSlug = clean
  782. End Function
  783. Function GetRawJsonFromRequest()
  784. Dim stream, rawJson
  785. Set stream = Server.CreateObject("ADODB.Stream")
  786. stream.Type = 1 ' adTypeBinary
  787. stream.Open
  788. stream.Write Request.BinaryRead(Request.TotalBytes)
  789. stream.Position = 0
  790. stream.Type = 2 ' adTypeText
  791. stream.Charset = "utf-8"
  792. rawJson = stream.ReadText
  793. stream.Close
  794. Set stream = Nothing
  795. GetRawJsonFromRequest = rawJson
  796. End Function
  797. Function EnsureFolderExists(ByVal folderPath)
  798. Dim fso, parentPath
  799. Set fso = Server.CreateObject("Scripting.FileSystemObject")
  800. If Len(Trim(CStr(folderPath))) = 0 Then
  801. EnsureFolderExists = False
  802. Exit Function
  803. End If
  804. If Not fso.FolderExists(folderPath) Then
  805. parentPath = fso.GetParentFolderName(folderPath)
  806. If Len(parentPath) > 0 And Not fso.FolderExists(parentPath) Then
  807. Call EnsureFolderExists(parentPath)
  808. End If
  809. If Not fso.FolderExists(folderPath) Then
  810. fso.CreateFolder folderPath
  811. End If
  812. End If
  813. EnsureFolderExists = True
  814. End Function
  815. Function FileExists(ByVal filePath)
  816. Dim fso
  817. Set fso = Server.CreateObject("Scripting.FileSystemObject")
  818. FileExists = fso.FileExists(filePath)
  819. End Function
  820. Function BuildAiImageFileName(ByVal prompt)
  821. Dim slug, stamp
  822. slug = GenerateSlug(prompt)
  823. If Len(slug) = 0 Then slug = "image"
  824. If Len(slug) > 40 Then slug = Left(slug, 40)
  825. stamp = Year(Now()) & Right("0" & Month(Now()), 2) & Right("0" & Day(Now()), 2) & _
  826. Right("0" & Hour(Now()), 2) & Right("0" & Minute(Now()), 2) & Right("0" & Second(Now()), 2)
  827. BuildAiImageFileName = slug & "-" & stamp & ".jpg"
  828. End Function
  829. Function GetOrCreateAiImageUrl(ByVal prompt)
  830. Dim cleanPrompt, folderPath, fileName, filePath, localUrl, remoteUrl, shell, command, exitCode
  831. cleanPrompt = Trim(CStr(prompt))
  832. If Len(cleanPrompt) = 0 Then
  833. GetOrCreateAiImageUrl = ""
  834. Exit Function
  835. End If
  836. folderPath = Server.MapPath("/uploads/ai-images")
  837. Call EnsureFolderExists(folderPath)
  838. fileName = BuildAiImageFileName(cleanPrompt)
  839. filePath = folderPath & "\" & fileName
  840. localUrl = "/uploads/ai-images/" & fileName
  841. If FileExists(filePath) Then
  842. GetOrCreateAiImageUrl = localUrl
  843. Exit Function
  844. End If
  845. remoteUrl = GetAiImageRemoteUrl(cleanPrompt)
  846. If Len(remoteUrl) = 0 Then
  847. GetOrCreateAiImageUrl = ""
  848. Exit Function
  849. End If
  850. On Error Resume Next
  851. Set shell = Server.CreateObject("WScript.Shell")
  852. If Err.Number = 0 Then
  853. command = "cmd /c curl.exe -L --fail --silent --show-error --output """ & filePath & """ """ & remoteUrl & """"
  854. exitCode = shell.Run(command, 0, True)
  855. If exitCode = 0 And FileExists(filePath) Then
  856. GetOrCreateAiImageUrl = localUrl
  857. Exit Function
  858. End If
  859. End If
  860. Err.Clear
  861. On Error GoTo 0
  862. GetOrCreateAiImageUrl = remoteUrl
  863. End Function
  864. Function Active(controllerName)
  865. On Error Resume Next
  866. If Replace(Lcase(router.Resolve(Request.ServerVariables("REQUEST_METHOD"), TrimQueryParams(Request.ServerVariables("HTTP_X_ORIGINAL_URL")))(0)),"controller","") = LCase(controllerName) Then
  867. Active = "active"
  868. Else
  869. Active = ""
  870. End If
  871. On Error GoTo 0
  872. End Function
  873. '====================================================================
  874. ' FormatDateForSql
  875. ' Converts a VBScript Date to a SQL Server-compatible string
  876. ' Output: 'YYYY-MM-DD HH:MM:SS'
  877. '====================================================================
  878. Function FormatDateForSql(vbDate)
  879. If IsNull(vbDate) Or vbDate = "" Then
  880. FormatDateForSql = "NULL"
  881. Exit Function
  882. End If
  883. ' Ensure vbDate is a valid date
  884. If Not IsDate(vbDate) Then
  885. Err.Raise vbObjectError + 1000, "FormatDateForSql", "Invalid date: " & vbDate
  886. End If
  887. Dim yyyy, mm, dd, hh, nn, ss
  888. yyyy = Year(vbDate)
  889. mm = Right("0" & Month(vbDate), 2)
  890. dd = Right("0" & Day(vbDate), 2)
  891. hh = Right("0" & Hour(vbDate), 2)
  892. nn = Right("0" & Minute(vbDate), 2)
  893. ss = Right("0" & Second(vbDate), 2)
  894. ' Construct SQL Server datetime literal
  895. FormatDateForSql = "'" & yyyy & "-" & mm & "-" & dd & " " & hh & ":" & nn & ":" & ss & "'"
  896. End Function
  897. %>

Powered by TurnKey Linux.