Add support for missing posts
Posts, like 8661f4724aa9, can go missing if the account or post was removed. In this case, the API returns data like this: ```json { "data": { "post": null } } ``` When this happens, we can detect it because the parsed response now has a nil value: `response.data.post == nil` and construct an `EmptyPage` instead of a `Page`. The `Articles::Show` action can then render conditionally based on if the response from `PageConverter` is a `Page` or an `EmptyPage`.
This commit is contained in:
parent
1dcded9153
commit
f05a12a880
11 changed files with 102 additions and 59 deletions
|
@ -1,5 +1,9 @@
|
|||
2022-05-21
|
||||
|
||||
* Show error page for missing posts
|
||||
|
||||
2022-05-21
|
||||
|
||||
* Remove the need for a fake DATABASE_URL
|
||||
|
||||
2022-04-04
|
||||
|
|
15
spec/actions/articles/show_spec.cr
Normal file
15
spec/actions/articles/show_spec.cr
Normal file
|
@ -0,0 +1,15 @@
|
|||
require "../../spec_helper"
|
||||
|
||||
include ActionHelpers
|
||||
|
||||
describe Articles::Show do
|
||||
context "if the article is missing" do
|
||||
it "should raise a MissingPageError" do
|
||||
context = action_context(path: "/abc123")
|
||||
|
||||
expect_raises(MissingPageError) do
|
||||
Articles::Show.new(context, params).call
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -17,8 +17,8 @@ describe PageConverter do
|
|||
}
|
||||
]
|
||||
JSON
|
||||
data_json = default_data_json(title, paragraph_json)
|
||||
data = PostResponse::Data.from_json(data_json)
|
||||
data_json = default_post_json(title, paragraph_json)
|
||||
data = PostResponse::Post.from_json(data_json)
|
||||
|
||||
page = PageConverter.new.convert(data)
|
||||
|
||||
|
@ -26,52 +26,48 @@ describe PageConverter do
|
|||
end
|
||||
|
||||
it "sets the author" do
|
||||
data_json = <<-JSON
|
||||
post_json = <<-JSON
|
||||
{
|
||||
"post": {
|
||||
"title": "This is a story",
|
||||
"createdAt": 0,
|
||||
"creator": {
|
||||
"id": "abc123",
|
||||
"name": "Author"
|
||||
},
|
||||
"content": {
|
||||
"bodyModel": {
|
||||
"paragraphs": []
|
||||
}
|
||||
"title": "This is a story",
|
||||
"createdAt": 0,
|
||||
"creator": {
|
||||
"id": "abc123",
|
||||
"name": "Author"
|
||||
},
|
||||
"content": {
|
||||
"bodyModel": {
|
||||
"paragraphs": []
|
||||
}
|
||||
}
|
||||
}
|
||||
JSON
|
||||
data = PostResponse::Data.from_json(data_json)
|
||||
post = PostResponse::Post.from_json(post_json)
|
||||
|
||||
page = PageConverter.new.convert(data)
|
||||
page = PageConverter.new.convert(post)
|
||||
|
||||
page.author.name.should eq "Author"
|
||||
page.author.id.should eq "abc123"
|
||||
end
|
||||
|
||||
it "sets the publish date/time" do
|
||||
data_json = <<-JSON
|
||||
post_json = <<-JSON
|
||||
{
|
||||
"post": {
|
||||
"title": "This is a story",
|
||||
"createdAt": 1000,
|
||||
"creator": {
|
||||
"id": "abc123",
|
||||
"name": "Author"
|
||||
},
|
||||
"content": {
|
||||
"bodyModel": {
|
||||
"paragraphs": []
|
||||
}
|
||||
"title": "This is a story",
|
||||
"createdAt": 1000,
|
||||
"creator": {
|
||||
"id": "abc123",
|
||||
"name": "Author"
|
||||
},
|
||||
"content": {
|
||||
"bodyModel": {
|
||||
"paragraphs": []
|
||||
}
|
||||
}
|
||||
}
|
||||
JSON
|
||||
data = PostResponse::Data.from_json(data_json)
|
||||
post = PostResponse::Post.from_json(post_json)
|
||||
|
||||
page = PageConverter.new.convert(data)
|
||||
page = PageConverter.new.convert(post)
|
||||
|
||||
page.created_at.should eq Time.utc(1970, 1, 1, 0, 0, 1)
|
||||
end
|
||||
|
@ -98,8 +94,8 @@ describe PageConverter do
|
|||
}
|
||||
]
|
||||
JSON
|
||||
data_json = default_data_json(title, paragraph_json)
|
||||
data = PostResponse::Data.from_json(data_json)
|
||||
post_json = default_post_json(title, paragraph_json)
|
||||
data = PostResponse::Post.from_json(post_json)
|
||||
|
||||
page = PageConverter.new.convert(data)
|
||||
|
||||
|
@ -115,23 +111,21 @@ def default_paragraph_json
|
|||
"[]"
|
||||
end
|
||||
|
||||
def default_data_json(
|
||||
def default_post_json(
|
||||
title : String = "This is a story",
|
||||
paragraph_json : String = default_paragraph_json
|
||||
)
|
||||
<<-JSON
|
||||
{
|
||||
"post": {
|
||||
"title": "#{title}",
|
||||
"createdAt": 1628974309758,
|
||||
"creator": {
|
||||
"id": "abc123",
|
||||
"name": "Author"
|
||||
},
|
||||
"content": {
|
||||
"bodyModel": {
|
||||
"paragraphs": #{paragraph_json}
|
||||
}
|
||||
"title": "#{title}",
|
||||
"createdAt": 1628974309758,
|
||||
"creator": {
|
||||
"id": "abc123",
|
||||
"name": "Author"
|
||||
},
|
||||
"content": {
|
||||
"bodyModel": {
|
||||
"paragraphs": #{paragraph_json}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
Spec.before_each do
|
||||
AppDatabase.truncate
|
||||
end
|
12
spec/support/action_helpers.cr
Normal file
12
spec/support/action_helpers.cr
Normal file
|
@ -0,0 +1,12 @@
|
|||
module ActionHelpers
|
||||
private def action_context(path = "/")
|
||||
io = IO::Memory.new
|
||||
request = HTTP::Request.new("GET", path)
|
||||
response = HTTP::Server::Response.new(io)
|
||||
HTTP::Server::Context.new(request, response)
|
||||
end
|
||||
|
||||
private def params
|
||||
{} of String => String
|
||||
end
|
||||
end
|
|
@ -6,8 +6,8 @@ class Articles::Show < BrowserAction
|
|||
case post_id
|
||||
in Monads::Just
|
||||
response = client_class.post_data(post_id.value!)
|
||||
page = PageConverter.new.convert(response.data)
|
||||
html ShowPage, page: page
|
||||
page = PageConverter.new.convert(response.data.post)
|
||||
render_page(page)
|
||||
in Monads::Nothing, Monads::Maybe
|
||||
html(
|
||||
Errors::ParseErrorPage,
|
||||
|
@ -18,6 +18,14 @@ class Articles::Show < BrowserAction
|
|||
end
|
||||
end
|
||||
|
||||
def render_page(page : Page)
|
||||
html ShowPage, page: page
|
||||
end
|
||||
|
||||
def render_page(page : MissingPage)
|
||||
raise MissingPageError.new
|
||||
end
|
||||
|
||||
def client_class
|
||||
if use_local?
|
||||
LocalClient
|
||||
|
|
|
@ -4,6 +4,10 @@ class Errors::Show < Lucky::ErrorAction
|
|||
default_format :html
|
||||
dont_report [Lucky::RouteNotFoundError, Avram::RecordNotFoundError]
|
||||
|
||||
def render(error : MissingPageError)
|
||||
error_html message: "This article is missing.", status: 404
|
||||
end
|
||||
|
||||
def render(error : Lucky::RouteNotFoundError | Avram::RecordNotFoundError)
|
||||
if html?
|
||||
error_html "Sorry, we couldn't find that page.", status: 404
|
||||
|
|
|
@ -1,20 +1,24 @@
|
|||
class PageConverter
|
||||
def convert(data : PostResponse::Data) : Page
|
||||
title, content = title_and_content(data)
|
||||
author = data.post.creator
|
||||
created_at = Time.unix_ms(data.post.createdAt)
|
||||
def convert(post : PostResponse::Post) : Page
|
||||
title, content = title_and_content(post)
|
||||
author = post.creator
|
||||
created_at = Time.unix_ms(post.createdAt)
|
||||
gist_store = gist_store(content)
|
||||
Page.new(
|
||||
title: title,
|
||||
author: author,
|
||||
created_at: Time.unix_ms(data.post.createdAt),
|
||||
created_at: Time.unix_ms(post.createdAt),
|
||||
nodes: ParagraphConverter.new.convert(content, gist_store)
|
||||
)
|
||||
end
|
||||
|
||||
def title_and_content(data : PostResponse::Data) : {String, Array(PostResponse::Paragraph)}
|
||||
title = data.post.title
|
||||
paragraphs = data.post.content.bodyModel.paragraphs
|
||||
def convert(post : Nil) : MissingPage
|
||||
MissingPage.new
|
||||
end
|
||||
|
||||
def title_and_content(post : PostResponse::Post) : {String, Array(PostResponse::Paragraph)}
|
||||
title = post.title
|
||||
paragraphs = post.content.bodyModel.paragraphs
|
||||
non_content_paragraphs = paragraphs.reject { |para| para.text == title }
|
||||
{title, non_content_paragraphs}
|
||||
end
|
||||
|
|
5
src/models/missing_page.cr
Normal file
5
src/models/missing_page.cr
Normal file
|
@ -0,0 +1,5 @@
|
|||
class MissingPage
|
||||
end
|
||||
|
||||
class MissingPageError < Exception
|
||||
end
|
|
@ -8,7 +8,7 @@ class PostResponse
|
|||
end
|
||||
|
||||
class Data < Base
|
||||
property post : Post
|
||||
property post : Post?
|
||||
end
|
||||
|
||||
class Post < Base
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
module Scribe
|
||||
VERSION = "2022-05-21"
|
||||
VERSION = "2022-06-17"
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue