More details on posts and error reporting
This commit is contained in:
2
Gemfile
2
Gemfile
@@ -49,6 +49,8 @@ gem "connection_pool"
|
||||
gem "omdb-api", require: false
|
||||
gem "image_processing", "~> 1.0"
|
||||
|
||||
gem "sentry-ruby"
|
||||
|
||||
group :cli, :development do
|
||||
gem "hanami-reloader"
|
||||
end
|
||||
|
@@ -405,6 +405,8 @@ GEM
|
||||
sanitize (6.0.1)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.12.0)
|
||||
sentry-ruby (5.9.0)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
sequel (5.68.0)
|
||||
shellany (0.0.1)
|
||||
simple-rss (1.3.3)
|
||||
@@ -500,6 +502,7 @@ DEPENDENCIES
|
||||
ruby-readability
|
||||
sanitize
|
||||
scraperd!
|
||||
sentry-ruby
|
||||
slim
|
||||
standardrb
|
||||
time_math2
|
||||
|
@@ -9,12 +9,17 @@ require "dry/matcher/result_matcher"
|
||||
|
||||
module Adamantium
|
||||
class Action < Hanami::Action
|
||||
include Deps["logger", "settings", not_found_view: "views.not_found"]
|
||||
include Deps["logger",
|
||||
"settings",
|
||||
not_found_view: "views.not_found",
|
||||
error_view: "views.error",
|
||||
sentry: "sentry.client"]
|
||||
|
||||
include Dry::Matcher.for(:handle, with: Dry::Matcher::ResultMatcher)
|
||||
include Dry::Monads[:result]
|
||||
|
||||
handle_exception ROM::TupleCountMismatchError => :not_found
|
||||
handle_exception StandardError => :handle_error
|
||||
|
||||
def authenticate!(req, res)
|
||||
if Hanami.env == :development || Hanami.env == :test
|
||||
@@ -47,6 +52,16 @@ module Adamantium
|
||||
res.render not_found_view
|
||||
end
|
||||
|
||||
def handle_error(req, res, exception)
|
||||
raise exception if settings.raise_exceptions
|
||||
|
||||
sentry.capture_exception(exception)
|
||||
|
||||
res.status = 500
|
||||
res.render error_view
|
||||
res.headers["Cache-Control"] = "no-store, max-age=0"
|
||||
end
|
||||
|
||||
def verify_scope(req:, scope:)
|
||||
req.env[:scopes].include? scope
|
||||
end
|
||||
|
@@ -97,6 +97,16 @@ module Adamantium
|
||||
:post
|
||||
end
|
||||
|
||||
def posted_in
|
||||
if name.nil?
|
||||
:statuses
|
||||
elsif location.nil?
|
||||
:posts
|
||||
else
|
||||
:places
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# e.g. geo:-37.75188,144.90417;u=35
|
||||
|
@@ -27,6 +27,9 @@ div class="max-w-prose mx-auto text-gray-600 dark:text-gray-200 flex"
|
||||
= "Published "
|
||||
time class="dt-published" datetime=bookmark.machine_published_at
|
||||
= bookmark.display_published_at
|
||||
p
|
||||
span in
|
||||
a class="hover:underline" href="/bookmarks" bookmarks
|
||||
|
||||
span class="text-right flex-1"
|
||||
== render "shared/tags", tags: bookmark.tags
|
||||
|
2
app/templates/error.html.slim
Normal file
2
app/templates/error.html.slim
Normal file
@@ -0,0 +1,2 @@
|
||||
div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200"
|
||||
h1 There was an error!
|
@@ -4,16 +4,16 @@ div class="mb-12 max-w-prose mx-auto text-gray-800 dark:text-gray-200"
|
||||
h2 class="text-xl" Explore posts
|
||||
|
||||
div class="grid grid-cols-4 grid-flow-col gap-2 mb-6"
|
||||
a class="block p-1 border border-lime-200 bg-lime-200 text-lime-900 hover:bg-lime-300 text-center rounded-lg" href="/tags" 🔖 By tag
|
||||
/ a class="block p-1 border border-lime-200 bg-lime-300 text-lime-900 hover:bg-lime-200 text-center rounded-lg" href="/years" 🗓️ By year
|
||||
a class="block p-1 border border-lime-200 bg-lime-200 text-lime-900 hover:bg-lime-300 text-center rounded-lg" href="/posts" 🪧 All posts
|
||||
a class="block p-1 border border-blue-200 bg-blue-200 text-blue-900 hover:bg-blue-300 text-center rounded-lg" href="/tags" 🔖 By tag
|
||||
/ a class="block p-1 border border-blue-200 bg-blue-300 text-blue-900 hover:bg-blue-200 text-center rounded-lg" href="/years" 🗓️ By year
|
||||
a class="block p-1 border border-blue-200 bg-blue-200 text-blue-900 hover:bg-blue-300 text-center rounded-lg" href="/posts" 🪧 All posts
|
||||
|
||||
h2 class="text-xl" Explore everything else
|
||||
|
||||
div class="grid grid-cols-4 grid-flow-col gap-2 mb-6"
|
||||
a class="block p-1 border border-lime-200 bg-lime-200 text-lime-900 hover:bg-lime-300 text-center rounded-lg" href="/colophon" 🧱 Colophon
|
||||
a class="block p-1 border border-lime-200 bg-lime-200 text-lime-900 hover:bg-lime-300 text-center rounded-lg" href="/hikes" 🥾 Hikes
|
||||
a class="block p-1 border border-lime-200 bg-lime-200 text-lime-900 hover:bg-lime-300 text-center rounded-lg" href="/movies" 🍿 Movies
|
||||
a class="block p-1 border border-lime-200 bg-lime-200 text-lime-900 hover:bg-lime-300 text-center rounded-lg" href="/trips" 🛫 Trips
|
||||
/ a class="block p-1 border border-lime-200 bg-lime-300 text-lime-900 hover:bg-lime-200 text-center rounded-lg" href="/art" 🎨 Art things
|
||||
a class="block p-1 border border-blue-200 bg-blue-200 text-blue-900 hover:bg-blue-300 text-center rounded-lg" href="/colophon" 🧱 Colophon
|
||||
a class="block p-1 border border-blue-200 bg-blue-200 text-blue-900 hover:bg-blue-300 text-center rounded-lg" href="/hikes" 🥾 Hikes
|
||||
a class="block p-1 border border-blue-200 bg-blue-200 text-blue-900 hover:bg-blue-300 text-center rounded-lg" href="/movies" 🍿 Movies
|
||||
a class="block p-1 border border-blue-200 bg-blue-200 text-blue-900 hover:bg-blue-300 text-center rounded-lg" href="/trips" 🛫 Trips
|
||||
/ a class="block p-1 border border-blue-200 bg-blue-300 text-blue-900 hover:bg-blue-200 text-center rounded-lg" href="/art" 🎨 Art things
|
||||
|
||||
|
@@ -1,3 +1,2 @@
|
||||
div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200"
|
||||
h1 Not Found!
|
||||
|
||||
|
@@ -89,6 +89,14 @@ article class="h-entry"
|
||||
p
|
||||
a class="p-author h-card" href=Hanami.app.settings.micropub_site_url
|
||||
= "by #{Hanami.app.settings.site_name}"
|
||||
p
|
||||
span in
|
||||
- if post.posted_in == :posts
|
||||
a class="hover:underline" href="/posts" posts
|
||||
- if post.posted_in == :places
|
||||
a class="hover:underline" href="/places" places
|
||||
- if post.posted_in == :statuses
|
||||
a class="hover:underline" href="/statuses" statuses
|
||||
span class="text-right flex-1 leading-6"
|
||||
== render "shared/tags", tags: post.tags
|
||||
div class="mb-2 max-w-prose mx-auto text-gray-600 dark:text-gray-200 flex"
|
||||
|
6
app/views/error.rb
Normal file
6
app/views/error.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
module Adamantium
|
||||
module Views
|
||||
class Error < View
|
||||
end
|
||||
end
|
||||
end
|
14
config/providers/sentry.rb
Normal file
14
config/providers/sentry.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
require "sentry-ruby"
|
||||
|
||||
Hanami.app.register_provider :sentry, namespace: true do
|
||||
prepare do
|
||||
Sentry.init do |config|
|
||||
config.dsn = target["settings"].sentry_dsn
|
||||
config.traces_sample_rate = 0.25
|
||||
end
|
||||
end
|
||||
|
||||
start do
|
||||
register "client", Sentry
|
||||
end
|
||||
end
|
@@ -25,6 +25,7 @@ module Adamantium
|
||||
get "/post/top_tracks/:slug", to: "posts.top_tracks"
|
||||
get "/post/:slug", to: "posts.show"
|
||||
get "/posts", to: "posts.index"
|
||||
# get "/posts/archive", to: "posts.archive"
|
||||
get "/posts/archive/:year", to: "posts.archive"
|
||||
|
||||
get "/bookmarks", to: "bookmarks.index"
|
||||
@@ -82,6 +83,7 @@ module Adamantium
|
||||
get "/posts", to: "posts.index"
|
||||
delete "/posts/:id", to: "posts.delete"
|
||||
post "/posts/:id/archive", to: "posts.archive"
|
||||
post "/posts/:id/publish", to: "posts.publish"
|
||||
|
||||
get "/media", to: "photos.index"
|
||||
|
||||
|
@@ -50,5 +50,8 @@ module Adamantium
|
||||
|
||||
setting :basic_auth_username, default: nil
|
||||
setting :basic_auth_password, default: nil
|
||||
|
||||
setting :sentry_dsn, default: nil
|
||||
setting :raise_exceptions, default: true
|
||||
end
|
||||
end
|
||||
|
@@ -4,6 +4,7 @@ module Admin
|
||||
def list
|
||||
posts
|
||||
.where(post_type: "bookmark")
|
||||
.order(Sequel.lit("published_at desc"))
|
||||
.to_a
|
||||
end
|
||||
|
||||
|
@@ -38,6 +38,7 @@ module Admin
|
||||
def list
|
||||
posts
|
||||
.where(post_type: "post")
|
||||
.order(Sequel.lit("published_at desc"))
|
||||
.to_a
|
||||
end
|
||||
|
||||
@@ -45,6 +46,10 @@ module Admin
|
||||
posts.where(id: id).delete
|
||||
end
|
||||
|
||||
def publish(id:)
|
||||
posts.where(id: id).update(published_at: Time.now)
|
||||
end
|
||||
|
||||
def archive(id:)
|
||||
posts.where(id: id).update(published_at: nil)
|
||||
end
|
||||
|
@@ -1,17 +1,42 @@
|
||||
div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200"
|
||||
h1 Admin // Bookmarks
|
||||
|
||||
div class="max-w-prose mx-auto"
|
||||
|
||||
button class="rounded bg-blue-100 hover:bg-blue-200 text-blue-600 px-2 hover:cursor-pointer" hx-post="/admin/bookmarks/clean" Check for dead links
|
||||
|
||||
div class="max-w-prose mx-auto" x-data="{ activeTab: 0 }"
|
||||
- if running_jobs
|
||||
div class="text-center bg-blue-100 mb-4 p-2 rounded" Job already queued
|
||||
- else
|
||||
button class="block rounded bg-blue-100 hover:bg-blue-200 text-blue-600 mb-4 p-2 hover:cursor-pointer" hx-post="/admin/bookmarks/clean" Check for dead links
|
||||
div class="flex"
|
||||
a href="#" class="text-gray-200 cursor-pointer p-2 border-2 mr-2 rounded border-blue-400" :class="{ 'bg-blue-400 text-blue-900': activeTab === 0 }" @click="activeTab = 0" class="tab-control" Published
|
||||
a href="#" class="text-gray-200 cursor-pointer p-2 border-2 rounded border-blue-400" :class="{ 'bg-blue-400 text-blue-900': activeTab === 1 }" @click="activeTab = 1" class="tab-control" Un published
|
||||
table class="prose dark:prose-invert table-auto prose-a:text-blue-600 prose-a:no-underline"
|
||||
thead
|
||||
th Details
|
||||
th Date
|
||||
th colspan="2" Actions
|
||||
tbody
|
||||
- bookmarks.each do |bookmark|
|
||||
tbody class="{ 'active': activeTab === 0 }" x-show.transition.in.opacity.duration.600="activeTab === 0"
|
||||
- published_bookmarks.each do |bookmark|
|
||||
tr id="bookmark-#{bookmark.id}"
|
||||
td
|
||||
div
|
||||
= bookmark.name
|
||||
a class="no-underline" href=bookmark.url
|
||||
small class="text-gray-400 dark:text-gray-600" = bookmark.url
|
||||
div
|
||||
- if bookmark.cached_content
|
||||
a href="/bookmark/#{bookmark.slug}" View cached version
|
||||
span —
|
||||
button hx-post="/admin/bookmarks/cache/#{bookmark.id}" Re-cache
|
||||
- else
|
||||
button hx-post="/admin/bookmarks/cache/#{bookmark.id}" No cached content, cache now?
|
||||
td
|
||||
= bookmark.published_at&.strftime("%d %b %Y")
|
||||
td
|
||||
button class="text-red-600" hx-delete="/admin/bookmarks/#{bookmark.id}" hx-target="#bookmark-#{bookmark.id}" delete
|
||||
td
|
||||
button hx-post="/admin/bookmarks/#{bookmark.id}/archive" archive
|
||||
tbody class="{ 'active': activeTab === 1 }" x-show.transition.in.opacity.duration.600="activeTab === 1"
|
||||
- unpublished_bookmarks.each do |bookmark|
|
||||
tr id="bookmark-#{bookmark.id}"
|
||||
td
|
||||
div
|
||||
|
@@ -18,4 +18,4 @@ div class="mb-4 max-w-prose mx-auto prose dark:prose-invert"
|
||||
div class="rounded max-w-xs" x-data=""
|
||||
img class="rounded object-cover hover:opacity-80 h-48 w-48" src="/#{photo.gsub("public/", "")}"
|
||||
button class="hover:text-blue-400 p-2 bg-blue-100 rounded text-blue-600 mr-4 no-underline" @click="$clipboard('#{Hanami.app.settings.micropub_site_url}/#{photo.gsub("public/", "")}')" Copy URL
|
||||
button class="text-red-600 hover:text-red-400" Delete
|
||||
button class="text-red-600 hover:text-red-400" hx-delete="/admin/media/#{photo}" hx-target="#post-#{photo}" Delete
|
@@ -1,26 +1,43 @@
|
||||
div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200"
|
||||
h1 Admin // Posts
|
||||
|
||||
div class="max-w-prose mx-auto"
|
||||
table class="prose dark:prose-invert table-auto prose-a:text-blue-600 prose-a:no-underline"
|
||||
thead
|
||||
th Details
|
||||
th Date
|
||||
th colspan="2" Actions
|
||||
tbody
|
||||
- posts.each do |post|
|
||||
tr id="post-#{post.id}"
|
||||
td
|
||||
div
|
||||
= post.name
|
||||
a class="no-underline" href="/post/#{post.slug}"
|
||||
small class="text-gray-400 dark:text-gray-600" = post.slug
|
||||
td
|
||||
= post.published_at&.strftime("%d %b %Y")
|
||||
td
|
||||
button class="text-red-600" hx-delete="/admin/bookmarks/#{post.id}" hx-target="#post-#{post.id}" delete
|
||||
td
|
||||
button hx-post="/admin/bookmarks/#{post.id}/archive" unpublish
|
||||
div class="max-w-prose mx-auto" x-data="{ activeTab: 0 }"
|
||||
div class="flex"
|
||||
a href="#" class="text-gray-200 cursor-pointer p-2 border-2 mr-2 rounded border-blue-400" :class="{ 'bg-blue-400 text-blue-900': activeTab === 0 }" @click="activeTab = 0" class="tab-control" Published
|
||||
a href="#" class="text-gray-200 cursor-pointer p-2 border-2 rounded border-blue-400" :class="{ 'bg-blue-400 text-blue-900': activeTab === 1 }" @click="activeTab = 1" class="tab-control" Un published
|
||||
table class="prose dark:prose-invert table-auto prose-a:text-blue-600 prose-a:no-underline"
|
||||
thead
|
||||
th Details
|
||||
th Date
|
||||
th colspan="2" Actions
|
||||
tbody class="{ 'active': activeTab === 0 }" x-show.transition.in.opacity.duration.600="activeTab === 0"
|
||||
- published_posts.each do |post|
|
||||
tr id="post-#{post.id}"
|
||||
td
|
||||
div
|
||||
= post.name
|
||||
a class="no-underline" href="/post/#{post.slug}"
|
||||
small class="text-gray-400 dark:text-gray-600" = post.slug
|
||||
td
|
||||
= post.published_at&.strftime("%d %b %Y")
|
||||
td
|
||||
button class="text-red-600" hx-delete="/admin/posts/#{post.id}" hx-target="#post-#{post.id}" delete
|
||||
td
|
||||
button hx-post="/admin/posts/#{post.id}/archive" unpublish
|
||||
tbody class="{ 'active': activeTab === 1 }" x-show.transition.in.opacity.duration.600="activeTab === 1"
|
||||
- unpublished_posts.each do |post|
|
||||
tr id="post-#{post.id}"
|
||||
td
|
||||
div
|
||||
= post.name
|
||||
a class="no-underline" href="/post/#{post.slug}"
|
||||
small class="text-gray-400 dark:text-gray-600" = post.slug
|
||||
td
|
||||
= post.published_at&.strftime("%d %b %Y")
|
||||
td
|
||||
button class="text-red-600" hx-delete="/admin/posts/#{post.id}" hx-target="#post-#{post.id}" delete
|
||||
td
|
||||
button hx-post="/admin/posts/#{post.id}/publish" publish
|
||||
|
||||
div class="max-w-screen-md mx-auto border-t-4 border-solid border-gray-400 dark:border-gray-600"
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
require "que"
|
||||
|
||||
module Admin
|
||||
module Views
|
||||
module Bookmarks
|
||||
@@ -5,8 +7,21 @@ module Admin
|
||||
|
||||
include Deps["repos.bookmark_repo"]
|
||||
|
||||
expose :published_bookmarks do |bookmarks|
|
||||
bookmarks[0]
|
||||
end
|
||||
|
||||
expose :unpublished_bookmarks do |bookmarks|
|
||||
bookmarks[1]
|
||||
end
|
||||
|
||||
expose :bookmarks do
|
||||
bookmark_repo.list
|
||||
bookmark_repo.list.partition{|p| p.published_at }
|
||||
end
|
||||
|
||||
expose :running_jobs do
|
||||
Que.connection = Adamantium::Container["persistence.db"]
|
||||
Que.job_stats.any? { |job| job[:job_class] == Adamantium::Jobs::RemoveDeadBookmarks.name }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@@ -5,8 +5,16 @@ module Admin
|
||||
|
||||
include Deps["repos.post_repo"]
|
||||
|
||||
expose :published_posts do |posts|
|
||||
posts[0]
|
||||
end
|
||||
|
||||
expose :unpublished_posts do |posts|
|
||||
posts[1]
|
||||
end
|
||||
|
||||
expose :posts do
|
||||
post_repo.list
|
||||
post_repo.list.partition{|p| p.published_at }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Reference in New Issue
Block a user