From ac29afed19fd41bbf347e115071d38aeebf7feb2 Mon Sep 17 00:00:00 2001 From: Nano Date: Sat, 2 May 2026 22:09:17 -0400 Subject: [PATCH] Implement Posts feature: controller actions, views (via Codex) --- app/controllers/PostsController.asp | 159 ++++++++++++++++++++++----- app/repositories/PostsRepository.asp | 100 ++++++++++++++++- app/views/Posts/edit.asp | 40 +++++++ app/views/Posts/index.asp | 62 +++++++++++ app/views/Posts/new.asp | 36 ++++++ app/views/Posts/show.asp | 33 ++++++ 6 files changed, 400 insertions(+), 30 deletions(-) create mode 100644 app/views/Posts/edit.asp create mode 100644 app/views/Posts/index.asp create mode 100644 app/views/Posts/new.asp create mode 100644 app/views/Posts/show.asp diff --git a/app/controllers/PostsController.asp b/app/controllers/PostsController.asp index c02aea2..2b43df4 100644 --- a/app/controllers/PostsController.asp +++ b/app/controllers/PostsController.asp @@ -38,66 +38,173 @@ Class PostsController_Class ' Action: Index '--------------------------------------------------------------- Public Sub Index() - ' TODO: Implement Index action - Response.Write "Index action called" + Dim posts + Set posts = PostsRepository().FindAllWhere("IsPublished = 1", "PublishedDate DESC", 0, 20) + %> + + <% End Sub '--------------------------------------------------------------- ' Action: Show '--------------------------------------------------------------- - Public Sub Show(slug) - ' TODO: Implement Show action - Response.Write "Show called
" - Response.Write "Parameters:
" - Response.Write "slug = " & Server.HTMLEncode(CStr(slug)) & "
" + Public Sub Show(ByVal slug) + Dim matches + Set matches = PostsRepository().Find(Array("Slug", slug, "IsPublished", 1), Empty) + + If matches.Count = 0 Then + Response.Status = "404 Not Found" + %> + + <% + Exit Sub + End If + + Dim post + Set post = matches.Front() + %> + + <% End Sub '--------------------------------------------------------------- ' Action: New '--------------------------------------------------------------- Public Sub NewForm() - ' TODO: Implement NewForm action - Response.Write "NewForm action called" + %> + + <% End Sub '--------------------------------------------------------------- ' Action: Create '--------------------------------------------------------------- Public Sub Create() - ' TODO: Implement Create action - Response.Write "Create action called" + Dim title : title = Trim(Request.Form("Title")) + If Len(title) = 0 Then + Flash().AddError "Title is required." + Response.Redirect "/posts/new" + Exit Sub + End If + + Dim post + Set post = New POBO_Posts + + post.Title = title + post.Summary = Request.Form("Summary") + post.Body = Request.Form("Body") + post.CategoryID = FormNumberOrZero(Request.Form("CategoryID")) + post.Slug = BuildSlug(title) + post.CreatedDate = Now() + post.UpdatedDate = Now() + post.IsPublished = 0 + + PostsRepository().AddNew post + Flash().Success = "Post created." + Response.Redirect "/posts" End Sub '--------------------------------------------------------------- ' Action: Edit '--------------------------------------------------------------- - Public Sub Edit(id) - ' TODO: Implement Edit action - Response.Write "Edit called
" - Response.Write "Parameters:
" - Response.Write "id = " & Server.HTMLEncode(CStr(id)) & "
" + Public Sub Edit(ByVal id) + Dim post + On Error Resume Next + Set post = PostsRepository().FindByID(id) + If Err.Number <> 0 Then + Err.Clear + On Error GoTo 0 + Response.Status = "404 Not Found" + %> + + <% + Exit Sub + End If + On Error GoTo 0 + %> + + <% End Sub '--------------------------------------------------------------- ' Action: Update '--------------------------------------------------------------- - Public Sub Update(id) - ' TODO: Implement Update action - Response.Write "Update called
" - Response.Write "Parameters:
" - Response.Write "id = " & Server.HTMLEncode(CStr(id)) & "
" + Public Sub Update(ByVal id) + Dim post + On Error Resume Next + Set post = PostsRepository().FindByID(id) + If Err.Number <> 0 Then + Err.Clear + On Error GoTo 0 + Response.Status = "404 Not Found" + %> + + <% + Exit Sub + End If + On Error GoTo 0 + + Dim title : title = Trim(Request.Form("Title")) + If Len(title) = 0 Then + Flash().AddError "Title is required." + Response.Redirect "/posts/" & Server.URLEncode(CStr(id)) & "/edit" + Exit Sub + End If + + post.Title = title + post.Summary = Request.Form("Summary") + post.Body = Request.Form("Body") + post.CategoryID = FormNumberOrZero(Request.Form("CategoryID")) + post.Slug = BuildSlug(title) + post.UpdatedDate = Now() + + PostsRepository().Update post + Flash().Success = "Post updated." + Response.Redirect "/posts" End Sub '--------------------------------------------------------------- ' Action: Delete '--------------------------------------------------------------- - Public Sub Delete(id) - ' TODO: Implement Delete action - Response.Write "Delete called
" - Response.Write "Parameters:
" - Response.Write "id = " & Server.HTMLEncode(CStr(id)) & "
" + Public Sub Delete(ByVal id) + PostsRepository().Delete id + Flash().Success = "Post deleted." + Response.Redirect "/posts" End Sub + Private Function FormNumberOrZero(ByVal value) + If IsNumeric(value) Then + FormNumberOrZero = CLng(value) + Else + FormNumberOrZero = 0 + End If + End Function + + Private Function BuildSlug(ByVal value) + Dim raw : raw = LCase(Trim(CStr(value))) + Dim i, ch, slug, previousDash + slug = "" + previousDash = False + + For i = 1 To Len(raw) + ch = Mid(raw, i, 1) + If (ch >= "a" And ch <= "z") Or (ch >= "0" And ch <= "9") Then + slug = slug & ch + previousDash = False + ElseIf Not previousDash And Len(slug) > 0 Then + slug = slug & "-" + previousDash = True + End If + Next + + Do While Right(slug, 1) = "-" + slug = Left(slug, Len(slug) - 1) + Loop + + If Len(slug) = 0 Then slug = "post" + BuildSlug = slug + End Function + End Class ' Singleton instance diff --git a/app/repositories/PostsRepository.asp b/app/repositories/PostsRepository.asp index 3a50e60..db44fdb 100644 --- a/app/repositories/PostsRepository.asp +++ b/app/repositories/PostsRepository.asp @@ -27,6 +27,54 @@ Class PostsRepository_Class Set GetAll = Find(Empty, orderBy) End Function + Public Function FindAllWhere(ByVal where_clause, ByVal order_by, ByVal offset, ByVal limit) + Dim sql : sql = "Select [Body], [CategoryID], [CreatedDate], [IsPublished], [PostID], [PublishedDate], [Slug], [Summary], [Title], [UpdatedDate] FROM [Posts]" + Dim whereText : whereText = "" + If Not IsEmpty(where_clause) Then + If Not IsNull(where_clause) Then whereText = Trim(CStr(where_clause)) + End If + + If Len(whereText) > 0 Then + sql = sql & " WHERE " & whereText + End If + sql = sql & BuildOrderBy(order_by, "[PostID]") + + Dim offsetCount, limitCount + If IsNumeric(offset) Then + offsetCount = CLng(offset) + Else + offsetCount = 0 + End If + If offsetCount < 0 Then offsetCount = 0 + + If IsNumeric(limit) Then + limitCount = CLng(limit) + Else + limitCount = 0 + End If + + Dim rs : Set rs = DAL.Query(sql, Empty) + Dim list : Set list = new LinkedList_Class + Dim skipped, added + skipped = 0 + added = 0 + + Do Until rs.EOF + If skipped < offsetCount Then + skipped = skipped + 1 + ElseIf limitCount <= 0 Or added < limitCount Then + list.Push Automapper.AutoMap(rs, "POBO_Posts") + added = added + 1 + End If + + If limitCount > 0 And added >= limitCount Then Exit Do + rs.MoveNext + Loop + + Set FindAllWhere = list + Destroy rs + End Function + Public Function Find(where_kvarray, order_string_or_array) Dim sql : sql = "Select [Body], [CategoryID], [CreatedDate], [IsPublished], [PostID], [PublishedDate], [Slug], [Summary], [Title], [UpdatedDate] FROM [Posts]" Dim where_keys, where_values, i @@ -149,21 +197,65 @@ Class PostsRepository_Class QI = "[" & Replace(CStr(name), "]", "]]") & "]" End Function - Private Function BuildOrderBy(orderArg, defaultCol) + Private Function BuildOrderBy(ByVal orderArg, ByVal defaultCol) Dim s : s = "" - If IsEmpty(orderArg) Or IsNull(orderArg) Or orderArg = "" Then - s = " ORDER BY " & defaultCol & " ASC" - ElseIf IsArray(orderArg) Then + If IsArray(orderArg) Then Dim i : s = " ORDER BY " For i = 0 To UBound(orderArg) If i > 0 Then s = s & ", " s = s & QI(orderArg(i)) Next + ElseIf IsEmpty(orderArg) Then + s = " ORDER BY " & defaultCol & " ASC" + ElseIf IsNull(orderArg) Then + s = " ORDER BY " & defaultCol & " ASC" + ElseIf CStr(orderArg) = "" Then + s = " ORDER BY " & defaultCol & " ASC" + ElseIf IsSafeOrderExpression(orderArg) Then + Dim parts : parts = Split(Trim(CStr(orderArg)), " ") + s = " ORDER BY " & QI(parts(0)) + If UBound(parts) = 1 Then s = s & " " & UCase(parts(1)) Else s = " ORDER BY " & QI(orderArg) End If BuildOrderBy = s End Function + + Private Function IsSafeOrderExpression(ByVal orderArg) + Dim raw : raw = Trim(CStr(orderArg)) + Dim parts : parts = Split(raw, " ") + + IsSafeOrderExpression = False + If UBound(parts) < 0 Or UBound(parts) > 1 Then Exit Function + If Not IsSafeIdentifier(parts(0)) Then Exit Function + If UBound(parts) = 1 Then + If UCase(parts(1)) <> "ASC" And UCase(parts(1)) <> "DESC" Then Exit Function + End If + + IsSafeOrderExpression = True + End Function + + Private Function IsSafeIdentifier(ByVal value) + Dim i, ch + value = CStr(value) + If Len(value) = 0 Then + IsSafeIdentifier = False + Exit Function + End If + + For i = 1 To Len(value) + ch = Mid(value, i, 1) + If Not ((ch >= "a" And ch <= "z") Or _ + (ch >= "A" And ch <= "Z") Or _ + (ch >= "0" And ch <= "9") Or _ + ch = "_") Then + IsSafeIdentifier = False + Exit Function + End If + Next + + IsSafeIdentifier = True + End Function End Class Dim PostsRepository__Singleton diff --git a/app/views/Posts/edit.asp b/app/views/Posts/edit.asp new file mode 100644 index 0000000..3b0894a --- /dev/null +++ b/app/views/Posts/edit.asp @@ -0,0 +1,40 @@ +
+
+
+
+

Edit Post

+ +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + Cancel +
+
+ +
+ +
+
+
+
+
diff --git a/app/views/Posts/index.asp b/app/views/Posts/index.asp new file mode 100644 index 0000000..6464283 --- /dev/null +++ b/app/views/Posts/index.asp @@ -0,0 +1,62 @@ +
+
+

Posts

+

Published articles from ASPBlogBrainOrdure.

+
+ New Post +
+ +<% +Dim postIter, postItem, shownCount +Set postIter = posts.Iterator() +shownCount = 0 + +If posts.Count = 0 Then +%> +
No published posts are available yet.
+<% +Else +%> +
+ <% + Do While postIter.HasNext And shownCount < 20 + Set postItem = postIter.GetNext() + shownCount = shownCount + 1 + %> +
+
+
+
+

+ + <%= H(postItem.Title) %> + +

+ <% + Dim publishedText + publishedText = "" + If IsDate(postItem.PublishedDate) Then + If CDate(postItem.PublishedDate) > #1/1/1970# Then + publishedText = FormatDateTime(postItem.PublishedDate, vbLongDate) + End If + End If + + If Len(publishedText) > 0 Then + %> + <%= H(publishedText) %> + <% + End If + %> +
+

<%= H(postItem.Summary) %>

+ Read +
+
+
+ <% + Loop + %> +
+<% +End If +%> diff --git a/app/views/Posts/new.asp b/app/views/Posts/new.asp new file mode 100644 index 0000000..738b40b --- /dev/null +++ b/app/views/Posts/new.asp @@ -0,0 +1,36 @@ +
+
+
+
+

New Post

+ +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + Cancel +
+
+
+
+
+
diff --git a/app/views/Posts/show.asp b/app/views/Posts/show.asp new file mode 100644 index 0000000..653cbdb --- /dev/null +++ b/app/views/Posts/show.asp @@ -0,0 +1,33 @@ +
+
+ + +

<%= H(post.Title) %>

+ + <% + Dim publishedText + publishedText = "" + If IsDate(post.PublishedDate) Then + If CDate(post.PublishedDate) > #1/1/1970# Then + publishedText = FormatDateTime(post.PublishedDate, vbLongDate) + End If + End If + + If Len(publishedText) > 0 Then + %> +

<%= H(publishedText) %>

+ <% + End If + + Dim postBody + postBody = H(post.Body) + postBody = Replace(postBody, vbCrLf, "
") + postBody = Replace(postBody, vbCr, "
") + postBody = Replace(postBody, vbLf, "
") + %> + +
<%= postBody %>
+
+