ASP Classic blog framework - BrainOrdure
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

1097 wiersze
35KB

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

Powered by TurnKey Linux.