From 2c1122c9d7751551bae4c95af1f5d7cae49a05f3 Mon Sep 17 00:00:00 2001 From: Daniel Nitsikopoulos Date: Wed, 31 May 2023 22:12:48 +1000 Subject: [PATCH] More details on posts and error reporting --- Gemfile | 2 + Gemfile.lock | 3 + app/action.rb | 17 +++++- app/decorators/posts/decorator.rb | 10 ++++ app/templates/bookmarks/show.html.slim | 3 + app/templates/error.html.slim | 2 + app/templates/more/index.html.slim | 16 +++--- app/templates/not_found.html.slim | 1 - app/templates/posts/show.html.slim | 8 +++ app/views/error.rb | 6 ++ config/providers/sentry.rb | 14 +++++ config/routes.rb | 2 + config/settings.rb | 3 + slices/admin/repos/bookmark_repo.rb | 1 + slices/admin/repos/post_repo.rb | 5 ++ .../admin/templates/bookmarks/index.html.slim | 37 ++++++++++-- slices/admin/templates/photos/index.html.slim | 2 +- slices/admin/templates/posts/index.html.slim | 57 ++++++++++++------- slices/admin/views/bookmarks/index.rb | 17 +++++- slices/admin/views/posts/index.rb | 10 +++- 20 files changed, 177 insertions(+), 39 deletions(-) create mode 100644 app/templates/error.html.slim create mode 100644 app/views/error.rb create mode 100644 config/providers/sentry.rb diff --git a/Gemfile b/Gemfile index c274cc2..8ad82db 100644 --- a/Gemfile +++ b/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 diff --git a/Gemfile.lock b/Gemfile.lock index b5c9802..e974a94 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -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 diff --git a/app/action.rb b/app/action.rb index 6218674..3461082 100644 --- a/app/action.rb +++ b/app/action.rb @@ -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 diff --git a/app/decorators/posts/decorator.rb b/app/decorators/posts/decorator.rb index 10afc11..33ebcd2 100644 --- a/app/decorators/posts/decorator.rb +++ b/app/decorators/posts/decorator.rb @@ -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 diff --git a/app/templates/bookmarks/show.html.slim b/app/templates/bookmarks/show.html.slim index ac04c66..7da024f 100644 --- a/app/templates/bookmarks/show.html.slim +++ b/app/templates/bookmarks/show.html.slim @@ -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 diff --git a/app/templates/error.html.slim b/app/templates/error.html.slim new file mode 100644 index 0000000..5d4760f --- /dev/null +++ b/app/templates/error.html.slim @@ -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! diff --git a/app/templates/more/index.html.slim b/app/templates/more/index.html.slim index f71d0a3..8c2f301 100644 --- a/app/templates/more/index.html.slim +++ b/app/templates/more/index.html.slim @@ -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 diff --git a/app/templates/not_found.html.slim b/app/templates/not_found.html.slim index e87e6cc..0eeb0e1 100644 --- a/app/templates/not_found.html.slim +++ b/app/templates/not_found.html.slim @@ -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! - diff --git a/app/templates/posts/show.html.slim b/app/templates/posts/show.html.slim index 7f5cb29..48256a0 100644 --- a/app/templates/posts/show.html.slim +++ b/app/templates/posts/show.html.slim @@ -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" diff --git a/app/views/error.rb b/app/views/error.rb new file mode 100644 index 0000000..de16070 --- /dev/null +++ b/app/views/error.rb @@ -0,0 +1,6 @@ +module Adamantium + module Views + class Error < View + end + end +end diff --git a/config/providers/sentry.rb b/config/providers/sentry.rb new file mode 100644 index 0000000..2e3f5c0 --- /dev/null +++ b/config/providers/sentry.rb @@ -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 diff --git a/config/routes.rb b/config/routes.rb index 44389c7..335d88c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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" diff --git a/config/settings.rb b/config/settings.rb index f3afa9f..dce8029 100644 --- a/config/settings.rb +++ b/config/settings.rb @@ -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 diff --git a/slices/admin/repos/bookmark_repo.rb b/slices/admin/repos/bookmark_repo.rb index dd71b40..8a9550b 100644 --- a/slices/admin/repos/bookmark_repo.rb +++ b/slices/admin/repos/bookmark_repo.rb @@ -4,6 +4,7 @@ module Admin def list posts .where(post_type: "bookmark") + .order(Sequel.lit("published_at desc")) .to_a end diff --git a/slices/admin/repos/post_repo.rb b/slices/admin/repos/post_repo.rb index 71171ff..2e22419 100644 --- a/slices/admin/repos/post_repo.rb +++ b/slices/admin/repos/post_repo.rb @@ -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 diff --git a/slices/admin/templates/bookmarks/index.html.slim b/slices/admin/templates/bookmarks/index.html.slim index 9970977..49bb3c0 100644 --- a/slices/admin/templates/bookmarks/index.html.slim +++ b/slices/admin/templates/bookmarks/index.html.slim @@ -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 diff --git a/slices/admin/templates/photos/index.html.slim b/slices/admin/templates/photos/index.html.slim index 9c6429b..f704dc3 100644 --- a/slices/admin/templates/photos/index.html.slim +++ b/slices/admin/templates/photos/index.html.slim @@ -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 \ No newline at end of file + button class="text-red-600 hover:text-red-400" hx-delete="/admin/media/#{photo}" hx-target="#post-#{photo}" Delete \ No newline at end of file diff --git a/slices/admin/templates/posts/index.html.slim b/slices/admin/templates/posts/index.html.slim index 6414327..c0b0a57 100644 --- a/slices/admin/templates/posts/index.html.slim +++ b/slices/admin/templates/posts/index.html.slim @@ -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" diff --git a/slices/admin/views/bookmarks/index.rb b/slices/admin/views/bookmarks/index.rb index 8051912..fe10012 100644 --- a/slices/admin/views/bookmarks/index.rb +++ b/slices/admin/views/bookmarks/index.rb @@ -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 diff --git a/slices/admin/views/posts/index.rb b/slices/admin/views/posts/index.rb index d68a734..7365040 100644 --- a/slices/admin/views/posts/index.rb +++ b/slices/admin/views/posts/index.rb @@ -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