Add bookmark admin
This commit is contained in:
2
Gemfile
2
Gemfile
@@ -29,6 +29,8 @@ gem "gpx"
|
|||||||
gem "gnuplot"
|
gem "gnuplot"
|
||||||
gem "matrix"
|
gem "matrix"
|
||||||
|
|
||||||
|
gem "ruby-readability", :require => "readability"
|
||||||
|
gem "down"
|
||||||
gem "httparty"
|
gem "httparty"
|
||||||
gem "redcarpet"
|
gem "redcarpet"
|
||||||
gem "reverse_markdown"
|
gem "reverse_markdown"
|
||||||
|
@@ -76,6 +76,8 @@ GEM
|
|||||||
domain_name (0.5.20190701)
|
domain_name (0.5.20190701)
|
||||||
unf (>= 0.0.5, < 1.0.0)
|
unf (>= 0.0.5, < 1.0.0)
|
||||||
dotenv (2.8.1)
|
dotenv (2.8.1)
|
||||||
|
down (5.4.0)
|
||||||
|
addressable (~> 2.8)
|
||||||
dry-auto_inject (1.0.1)
|
dry-auto_inject (1.0.1)
|
||||||
dry-core (~> 1.0)
|
dry-core (~> 1.0)
|
||||||
zeitwerk (~> 2.6)
|
zeitwerk (~> 2.6)
|
||||||
@@ -165,6 +167,7 @@ GEM
|
|||||||
guard (~> 2.14)
|
guard (~> 2.14)
|
||||||
guard-compat (~> 1.2)
|
guard-compat (~> 1.2)
|
||||||
puma (>= 4.0, < 7)
|
puma (>= 4.0, < 7)
|
||||||
|
guess_html_encoding (0.0.11)
|
||||||
hanami (2.0.3)
|
hanami (2.0.3)
|
||||||
bundler (>= 1.16, < 3)
|
bundler (>= 1.16, < 3)
|
||||||
dry-configurable (~> 1.0, < 2)
|
dry-configurable (~> 1.0, < 2)
|
||||||
@@ -375,6 +378,9 @@ GEM
|
|||||||
rubocop (>= 1.7.0, < 2.0)
|
rubocop (>= 1.7.0, < 2.0)
|
||||||
rubocop-ast (>= 0.4.0)
|
rubocop-ast (>= 0.4.0)
|
||||||
ruby-progressbar (1.13.0)
|
ruby-progressbar (1.13.0)
|
||||||
|
ruby-readability (0.7.0)
|
||||||
|
guess_html_encoding (>= 0.0.4)
|
||||||
|
nokogiri (>= 1.6.0)
|
||||||
ruby2_keywords (0.0.5)
|
ruby2_keywords (0.0.5)
|
||||||
sanitize (6.0.1)
|
sanitize (6.0.1)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
@@ -433,6 +439,7 @@ DEPENDENCIES
|
|||||||
capistrano3-puma!
|
capistrano3-puma!
|
||||||
database_cleaner-sequel
|
database_cleaner-sequel
|
||||||
dotenv
|
dotenv
|
||||||
|
down
|
||||||
dry-matcher
|
dry-matcher
|
||||||
dry-monads
|
dry-monads
|
||||||
dry-types
|
dry-types
|
||||||
@@ -463,6 +470,7 @@ DEPENDENCIES
|
|||||||
rom-factory
|
rom-factory
|
||||||
rom-sql
|
rom-sql
|
||||||
ruby-filemagic!
|
ruby-filemagic!
|
||||||
|
ruby-readability
|
||||||
sanitize
|
sanitize
|
||||||
scraperd!
|
scraperd!
|
||||||
slim
|
slim
|
||||||
|
@@ -1,13 +1,20 @@
|
|||||||
div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200"
|
div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200"
|
||||||
h1 = bookmark.name
|
h1 = bookmark.name
|
||||||
|
|
||||||
div class="mb-12 prose max-w-prose mx-auto text-gray-800 dark:text-gray-200"
|
div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200" x-data="{ open: false }"
|
||||||
a class="text-blue-600 no-underline hover:underline" href=bookmark.url
|
a class="text-blue-600 no-underline hover:underline" href=bookmark.url
|
||||||
p class="text-xl"
|
p class="text-xl"
|
||||||
= bookmark.url
|
= bookmark.url
|
||||||
|
|
||||||
== bookmark.content
|
== bookmark.content
|
||||||
|
|
||||||
|
- unless bookmark.cached_content.nil?
|
||||||
|
button @click="open = ! open" Toggle cached version
|
||||||
|
|
||||||
|
span x-show="open"
|
||||||
|
div class="rounded bg-blue-50 px-4 py-2"
|
||||||
|
== bookmark.cached_content
|
||||||
|
|
||||||
div class="prose max-w-prose mx-auto text-gray-800 dark:text-gray-200 grid grid-cols-5 gap-2" hx-get="/bookmarks/metadata/#{bookmark.id}" hx-trigger="load"
|
div class="prose max-w-prose mx-auto text-gray-800 dark:text-gray-200 grid grid-cols-5 gap-2" hx-get="/bookmarks/metadata/#{bookmark.id}" hx-trigger="load"
|
||||||
|
|
||||||
div class="mb-8 max-w-screen-md mx-auto border-t-4 border-solid border-gray-400 dark:border-gray-600"
|
div class="mb-8 max-w-screen-md mx-auto border-t-4 border-solid border-gray-400 dark:border-gray-600"
|
||||||
|
@@ -28,6 +28,7 @@ html
|
|||||||
script src="/assets/index.js"
|
script src="/assets/index.js"
|
||||||
|
|
||||||
script src="https://unpkg.com/htmx.org@1.8.4" integrity="sha384-wg5Y/JwF7VxGk4zLsJEcAojRtlVp1FKKdGy1qN+OMtdq72WRvX/EdRdqg/LOhYeV" crossorigin="anonymous"
|
script src="https://unpkg.com/htmx.org@1.8.4" integrity="sha384-wg5Y/JwF7VxGk4zLsJEcAojRtlVp1FKKdGy1qN+OMtdq72WRvX/EdRdqg/LOhYeV" crossorigin="anonymous"
|
||||||
|
script src="https://cdn.jsdelivr.net/npm/alpinejs@3.12.0/dist/cdn.min.js" defer="true"
|
||||||
|
|
||||||
script src="https://api.mapbox.com/mapbox-gl-js/v2.9.1/mapbox-gl.js"
|
script src="https://api.mapbox.com/mapbox-gl-js/v2.9.1/mapbox-gl.js"
|
||||||
link href="https://api.mapbox.com/mapbox-gl-js/v2.9.1/mapbox-gl.css" rel="stylesheet"
|
link href="https://api.mapbox.com/mapbox-gl-js/v2.9.1/mapbox-gl.css" rel="stylesheet"
|
||||||
|
@@ -4,11 +4,12 @@ require "hanami"
|
|||||||
|
|
||||||
module Adamantium
|
module Adamantium
|
||||||
class App < Hanami::App
|
class App < Hanami::App
|
||||||
config.actions.content_security_policy[:script_src] += " https://gist.github.com"
|
config.actions.content_security_policy[:script_src] += " 'unsafe-eval' https://gist.github.com"
|
||||||
config.actions.content_security_policy[:script_src] += " *.dnitza.com"
|
config.actions.content_security_policy[:script_src] += " *.dnitza.com"
|
||||||
config.actions.content_security_policy[:script_src] += " https://api.mapbox.com/mapbox-gl-js/v2.9.1/mapbox-gl.js"
|
config.actions.content_security_policy[:script_src] += " https://api.mapbox.com/mapbox-gl-js/v2.9.1/mapbox-gl.js"
|
||||||
config.actions.content_security_policy[:media_src] += " https://dnitza.com"
|
config.actions.content_security_policy[:media_src] += " https://dnitza.com"
|
||||||
config.actions.content_security_policy[:script_src] += " https://unpkg.com/htmx.org@1.8.4 https://unpkg.com/htmx.org@1.9.2"
|
config.actions.content_security_policy[:script_src] += " https://unpkg.com/htmx.org@1.8.4 https://unpkg.com/htmx.org@1.9.2"
|
||||||
|
config.actions.content_security_policy[:script_src] += " https://cdn.jsdelivr.net/npm/alpinejs@3.12.0/dist/cdn.min.js"
|
||||||
config.actions.content_security_policy[:connect_src] += " https://stats.dnitza.com/api/event https://*.mapbox.com"
|
config.actions.content_security_policy[:connect_src] += " https://stats.dnitza.com/api/event https://*.mapbox.com"
|
||||||
config.actions.content_security_policy[:frame_src] += " https://embed.music.apple.com"
|
config.actions.content_security_policy[:frame_src] += " https://embed.music.apple.com"
|
||||||
config.actions.content_security_policy[:style_src] += " https://api.mapbox.com/mapbox-gl-js/v2.9.1/mapbox-gl.css"
|
config.actions.content_security_policy[:style_src] += " https://api.mapbox.com/mapbox-gl-js/v2.9.1/mapbox-gl.css"
|
||||||
|
@@ -65,6 +65,10 @@ module Adamantium
|
|||||||
get "/tags/auto_tagging/new", to: "auto_tagging.new"
|
get "/tags/auto_tagging/new", to: "auto_tagging.new"
|
||||||
post "/tags/auto_tagging", to: "auto_tagging.create"
|
post "/tags/auto_tagging", to: "auto_tagging.create"
|
||||||
delete "/tags/auto_taggings/:id", to: "auto_tagging.delete"
|
delete "/tags/auto_taggings/:id", to: "auto_tagging.delete"
|
||||||
|
|
||||||
|
get "/bookmarks", to: "bookmarks.index"
|
||||||
|
delete "/bookmarks/:id", to: "bookmarks.delete"
|
||||||
|
post "/bookmarks/cache/:id", to: "bookmarks.cache"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
9
db/migrate/20230507001217_add_cached_bookmark_to_post.rb
Normal file
9
db/migrate/20230507001217_add_cached_bookmark_to_post.rb
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
ROM::SQL.migration do
|
||||||
|
change do
|
||||||
|
alter_table(:posts) do
|
||||||
|
add_column :cached_content, :text
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
20
slices/admin/actions/bookmarks/cache.rb
Normal file
20
slices/admin/actions/bookmarks/cache.rb
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
module Admin
|
||||||
|
module Actions
|
||||||
|
module Bookmarks
|
||||||
|
class Cache < Action
|
||||||
|
|
||||||
|
include Deps["commands.bookmarks.cache"]
|
||||||
|
|
||||||
|
def handle(req, res)
|
||||||
|
bookmark_id = req.params[:id]
|
||||||
|
|
||||||
|
if cache.(bookmark_id: bookmark_id).success?
|
||||||
|
res.body = "Success"
|
||||||
|
else
|
||||||
|
res.body = "Failed"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
17
slices/admin/actions/bookmarks/delete.rb
Normal file
17
slices/admin/actions/bookmarks/delete.rb
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
module Admin
|
||||||
|
module Actions
|
||||||
|
module Bookmarks
|
||||||
|
class Delete < Action
|
||||||
|
|
||||||
|
include Deps["repos.bookmark_repo", "repos.post_tag_repo"]
|
||||||
|
|
||||||
|
def handle(req, res)
|
||||||
|
bookmark_id = req.params[:id]
|
||||||
|
|
||||||
|
post_tag_repo.delete_by_post_id(post_id: bookmark_id)
|
||||||
|
bookmark_repo.delete(id: bookmark_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
14
slices/admin/actions/bookmarks/index.rb
Normal file
14
slices/admin/actions/bookmarks/index.rb
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
module Admin
|
||||||
|
module Actions
|
||||||
|
module Bookmarks
|
||||||
|
class Index < Action
|
||||||
|
|
||||||
|
include Deps["views.bookmarks.index"]
|
||||||
|
|
||||||
|
def handle(req, res)
|
||||||
|
res.render index
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
25
slices/admin/commands/bookmarks/cache.rb
Normal file
25
slices/admin/commands/bookmarks/cache.rb
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
require "readability"
|
||||||
|
require "down"
|
||||||
|
|
||||||
|
module Admin
|
||||||
|
module Commands
|
||||||
|
module Bookmarks
|
||||||
|
class Cache
|
||||||
|
include Dry::Monads[:result]
|
||||||
|
include Deps["repos.bookmark_repo"]
|
||||||
|
|
||||||
|
def call(bookmark_id: )
|
||||||
|
bookmark = bookmark_repo.fetch(id: bookmark_id)
|
||||||
|
bookmark.url
|
||||||
|
|
||||||
|
tempfile = Down.download(bookmark.url)
|
||||||
|
content = Readability::Document.new(tempfile.read, tags: %w[div p h1 h2 h3 h4 h5 h6]).content
|
||||||
|
|
||||||
|
bookmark_repo.update(id: bookmark_id, cached_content: content)
|
||||||
|
|
||||||
|
Success()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
23
slices/admin/repos/bookmark_repo.rb
Normal file
23
slices/admin/repos/bookmark_repo.rb
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
module Admin
|
||||||
|
module Repos
|
||||||
|
class BookmarkRepo < Adamantium::Repo[:posts]
|
||||||
|
def list
|
||||||
|
posts
|
||||||
|
.where(post_type: "bookmark")
|
||||||
|
.to_a
|
||||||
|
end
|
||||||
|
|
||||||
|
def fetch(id:)
|
||||||
|
posts.where(id: id).one
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete(id:)
|
||||||
|
posts.where(id: id).delete
|
||||||
|
end
|
||||||
|
|
||||||
|
def update(id:, cached_content:)
|
||||||
|
posts.where(id: id).update(cached_content: cached_content)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@@ -5,6 +5,10 @@ module Admin
|
|||||||
def delete(tag_id:)
|
def delete(tag_id:)
|
||||||
post_tags.where(tag_id: tag_id).delete
|
post_tags.where(tag_id: tag_id).delete
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def delete_by_post_id(post_id:)
|
||||||
|
post_tags.where(post_id: post_id).delete
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
31
slices/admin/templates/bookmarks/index.html.slim
Normal file
31
slices/admin/templates/bookmarks/index.html.slim
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
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"
|
||||||
|
table class="prose dark:prose-invert table-auto prose-a:text-blue-600 prose-a:no-underline"
|
||||||
|
thead
|
||||||
|
th Details
|
||||||
|
th Date
|
||||||
|
th Actions
|
||||||
|
tbody
|
||||||
|
- 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
|
||||||
|
- else
|
||||||
|
button hx-post="/admin/bookmarks/cache/#{bookmark.id}" No cached content, cache now?
|
||||||
|
td
|
||||||
|
= bookmark.published_at&.strftime("%d %b %Y")
|
||||||
|
td
|
||||||
|
button hx-delete="/admin/bookmarks/#{bookmark.id}" hx-target="#bookmark-#{bookmark.id}" delete
|
||||||
|
|
||||||
|
div class="max-w-screen-md mx-auto border-t-4 border-solid border-gray-400 dark:border-gray-600"
|
||||||
|
|
||||||
|
|
||||||
|
|
@@ -7,6 +7,8 @@ div class="max-w-prose mx-auto prose dark:prose-invert"
|
|||||||
a href="/admin/tags" Tags
|
a href="/admin/tags" Tags
|
||||||
li
|
li
|
||||||
a href="/admin/tags/auto_tagging" Auto tagging
|
a href="/admin/tags/auto_tagging" Auto tagging
|
||||||
|
li
|
||||||
|
a href="/admin/bookmarks" Bookmarks
|
||||||
|
|
||||||
div class="max-w-screen-md mx-auto border-t-4 border-solid border-gray-400 dark:border-gray-600"
|
div class="max-w-screen-md mx-auto border-t-4 border-solid border-gray-400 dark:border-gray-600"
|
||||||
|
|
||||||
|
@@ -47,6 +47,8 @@ html
|
|||||||
a class="p-1 rounded text-gray-400 hover:bg-red-100 hover:text-red-400 dark:hover:bg-red-200 #{link_active?('about') ? 'text-red-600 dark:text-red-400' : ''}" href="/admin/tags" Tags
|
a class="p-1 rounded text-gray-400 hover:bg-red-100 hover:text-red-400 dark:hover:bg-red-200 #{link_active?('about') ? 'text-red-600 dark:text-red-400' : ''}" href="/admin/tags" Tags
|
||||||
span class="text-gray-400 dark:text-gray-600"
|
span class="text-gray-400 dark:text-gray-600"
|
||||||
= "/"
|
= "/"
|
||||||
|
a class="p-1 rounded text-gray-400 hover:bg-red-100 hover:text-red-400 dark:hover:bg-red-200 #{link_active?('about') ? 'text-red-600 dark:text-red-400' : ''}" href="/admin/bookmarks" Bookmarks
|
||||||
|
|
||||||
== yield
|
== yield
|
||||||
div class="px-4 max-w-screen-md mx-auto pb-10"
|
div class="px-4 max-w-screen-md mx-auto pb-10"
|
||||||
p class="float-left text-gray-200 dark:text-gray-600" © 2023 Daniel Nitsikopoulos. All rights reserved.
|
p class="float-left text-gray-200 dark:text-gray-600" © 2023 Daniel Nitsikopoulos. All rights reserved.
|
||||||
|
14
slices/admin/views/bookmarks/index.rb
Normal file
14
slices/admin/views/bookmarks/index.rb
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
module Admin
|
||||||
|
module Views
|
||||||
|
module Bookmarks
|
||||||
|
class Index < Admin::View
|
||||||
|
|
||||||
|
include Deps["repos.bookmark_repo"]
|
||||||
|
|
||||||
|
expose :bookmarks do
|
||||||
|
bookmark_repo.list
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Reference in New Issue
Block a user