Add auto tagger for posts
This commit is contained in:
31
app/commands/auto_tagging/tag.rb
Normal file
31
app/commands/auto_tagging/tag.rb
Normal file
@@ -0,0 +1,31 @@
|
||||
module Adamantium
|
||||
module Commands
|
||||
module AutoTagging
|
||||
class Tag
|
||||
include Dry::Monads[:result]
|
||||
include Deps["repos.post_repo", "repos.auto_tagging_repo"]
|
||||
|
||||
def call(auto_tag_id: nil)
|
||||
auto_taggings = if auto_tag_id
|
||||
auto_tagging_repo.find(auto_tag_id)
|
||||
else
|
||||
auto_tagging_repo.all
|
||||
end
|
||||
|
||||
auto_taggings.each do |auto_tagging|
|
||||
posts = auto_tagging.title_only? ?
|
||||
post_repo.by_title(title_contains: auto_tagging.title_contains) :
|
||||
post_repo.by_content(body_contains: auto_tagging.body_contains)
|
||||
|
||||
posts.each do |post|
|
||||
post_repo.auto_tag_post(post_id: post.id,
|
||||
tag_id: auto_tagging.tag_id)
|
||||
end
|
||||
end
|
||||
|
||||
Success()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@@ -10,6 +10,7 @@ module Adamantium
|
||||
syndicate: "commands.posts.syndicate",
|
||||
send_to_dayone: "syndication.dayone",
|
||||
send_webmentions: "commands.posts.send_webmentions",
|
||||
auto_tag: "commands.auto_tagging.tag",
|
||||
]
|
||||
|
||||
include Dry::Monads[:result]
|
||||
@@ -20,6 +21,8 @@ module Adamantium
|
||||
|
||||
syndicate.call(created_post.id, post)
|
||||
|
||||
auto_tag.call()
|
||||
|
||||
# decorated_post = Decorators::Posts::Decorator.new(created_post)
|
||||
|
||||
# send_webmentions.call(post_content: attrs[:content], post_url: decorated_post.permalink)
|
||||
|
13
app/entities/auto_tagging.rb
Normal file
13
app/entities/auto_tagging.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
module Adamantium
|
||||
module Entities
|
||||
class AutoTagging < Dry::Struct
|
||||
attribute? :title_contains, Types::Optional::String
|
||||
attribute? :body_contains, Types::Optional::String
|
||||
attribute :tag_id, Types::Coercible::Integer
|
||||
|
||||
def title_only?
|
||||
!title_contains.empty?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
18
app/repos/auto_tagging_repo.rb
Normal file
18
app/repos/auto_tagging_repo.rb
Normal file
@@ -0,0 +1,18 @@
|
||||
module Adamantium
|
||||
module Repos
|
||||
class AutoTaggingRepo < Adamantium::Repo[:auto_taggings]
|
||||
def find(id)
|
||||
auto_taggings
|
||||
.where(id: id)
|
||||
.map_to(Adamantium::Entities::AutoTagging)
|
||||
.to_a
|
||||
end
|
||||
|
||||
def all
|
||||
auto_taggings
|
||||
.map_to(Adamantium::Entities::AutoTagging)
|
||||
.to_a
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@@ -47,6 +47,38 @@ module Adamantium
|
||||
end
|
||||
end
|
||||
|
||||
def auto_tag_post(post_id:, tag_id:)
|
||||
|
||||
return if posts
|
||||
.post_tags
|
||||
.where(
|
||||
post_id: post_id,
|
||||
tag_id: tag_id
|
||||
).count > 0
|
||||
|
||||
posts
|
||||
.post_tags
|
||||
.changeset(:create, {
|
||||
post_id: post_id,
|
||||
tag_id: tag_id
|
||||
})
|
||||
.commit
|
||||
end
|
||||
|
||||
def by_title(title_contains:)
|
||||
posts
|
||||
.where(post_type: "post")
|
||||
.published
|
||||
.where(Sequel.ilike(:name, "%#{title_contains}%")).to_a
|
||||
end
|
||||
|
||||
def by_content(body_contains:)
|
||||
posts
|
||||
.where(post_type: "post")
|
||||
.published
|
||||
.where(Sequel.ilike(:content, "%#{body_contains}%")).to_a
|
||||
end
|
||||
|
||||
def remove_tag(post_id:, tag:)
|
||||
tag = posts.tags.where(label: tag).one
|
||||
|
||||
|
@@ -60,6 +60,11 @@ module Adamantium
|
||||
|
||||
get "/tags", to: "tags.index"
|
||||
delete "/tags/:id", to: "tags.delete"
|
||||
|
||||
get "/tags/auto_tagging", to: "auto_tagging.index"
|
||||
get "/tags/auto_tagging/new", to: "auto_tagging.new"
|
||||
post "/tags/auto_tagging", to: "auto_tagging.create"
|
||||
delete "/tags/auto_taggings/:id", to: "auto_tagging.delete"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
12
db/migrate/20230506081449_create_auto_taggings.rb
Normal file
12
db/migrate/20230506081449_create_auto_taggings.rb
Normal file
@@ -0,0 +1,12 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
ROM::SQL.migration do
|
||||
change do
|
||||
create_table(:auto_taggings) do
|
||||
primary_key :id
|
||||
column :title_contains, :text
|
||||
column :body_contains, :text
|
||||
foreign_key :tag_id, :tags, null: false
|
||||
end
|
||||
end
|
||||
end
|
17
lib/adamantium/persistence/relations/auto_taggings.rb
Normal file
17
lib/adamantium/persistence/relations/auto_taggings.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Adamantium
|
||||
module Persistence
|
||||
module Relations
|
||||
class AutoTaggings < ROM::Relation[:sql]
|
||||
schema :auto_taggings, infer: true do
|
||||
associations do
|
||||
belongs_to :tag
|
||||
end
|
||||
end
|
||||
|
||||
auto_struct(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
28
slices/admin/actions/auto_tagging/create.rb
Normal file
28
slices/admin/actions/auto_tagging/create.rb
Normal file
@@ -0,0 +1,28 @@
|
||||
module Admin
|
||||
module Actions
|
||||
module AutoTagging
|
||||
class Create < Action
|
||||
|
||||
include Deps["commands.auto_tagging.create",
|
||||
"views.auto_tagging.index",
|
||||
auto_tag: "commands.auto_tagging.tag"]
|
||||
|
||||
def handle(req, res)
|
||||
title_contains = req.params[:title_contains]
|
||||
body_contains = req.params[:body_contains]
|
||||
tag_id = req.params[:tag_id]
|
||||
|
||||
result = create.(title_contains: title_contains,
|
||||
body_contains: body_contains,
|
||||
tag_id: tag_id)
|
||||
|
||||
if result.success?
|
||||
auto_tag.(auto_tag_id: result.value!)
|
||||
end
|
||||
|
||||
res.render index
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
14
slices/admin/actions/auto_tagging/delete.rb
Normal file
14
slices/admin/actions/auto_tagging/delete.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
module Admin
|
||||
module Actions
|
||||
module AutoTagging
|
||||
class Delete < Action
|
||||
|
||||
include Deps["repos.auto_tagging_repo"]
|
||||
|
||||
def handle(req, res)
|
||||
auto_tagging_repo.delete(id: req.params[:id])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
14
slices/admin/actions/auto_tagging/index.rb
Normal file
14
slices/admin/actions/auto_tagging/index.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
module Admin
|
||||
module Actions
|
||||
module AutoTagging
|
||||
class Index < Action
|
||||
|
||||
include Deps["views.auto_tagging.index"]
|
||||
|
||||
def handle(req, res)
|
||||
res.render index
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
14
slices/admin/actions/auto_tagging/new.rb
Normal file
14
slices/admin/actions/auto_tagging/new.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
module Admin
|
||||
module Actions
|
||||
module AutoTagging
|
||||
class New < Action
|
||||
|
||||
include Deps[new_view: "views.auto_tagging.new"]
|
||||
|
||||
def handle(req, res)
|
||||
res.render new_view
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
20
slices/admin/commands/auto_tagging/create.rb
Normal file
20
slices/admin/commands/auto_tagging/create.rb
Normal file
@@ -0,0 +1,20 @@
|
||||
module Admin
|
||||
module Commands
|
||||
module AutoTagging
|
||||
class Create
|
||||
include Dry::Monads[:result]
|
||||
include Deps["repos.auto_tagging_repo"]
|
||||
|
||||
def call(title_contains:, body_contains:, tag_id:)
|
||||
Failure() if !title_contains.empty? && !body_contains.empty?
|
||||
|
||||
result = auto_tagging_repo.create(title_contains: title_contains,
|
||||
body_contains: body_contains,
|
||||
tag_id: tag_id)
|
||||
|
||||
Success(result.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
31
slices/admin/commands/auto_tagging/tag.rb
Normal file
31
slices/admin/commands/auto_tagging/tag.rb
Normal file
@@ -0,0 +1,31 @@
|
||||
module Admin
|
||||
module Commands
|
||||
module AutoTagging
|
||||
class Tag
|
||||
include Dry::Monads[:result]
|
||||
include Deps["repos.post_repo", "repos.auto_tagging_repo"]
|
||||
|
||||
def call(auto_tag_id: nil)
|
||||
auto_taggings = if auto_tag_id
|
||||
auto_tagging_repo.find(auto_tag_id)
|
||||
else
|
||||
auto_tagging_repo.all
|
||||
end
|
||||
|
||||
auto_taggings.each do |auto_tagging|
|
||||
posts = auto_tagging.title_only? ?
|
||||
post_repo.by_title(title_contains: auto_tagging.title_contains) :
|
||||
post_repo.by_content(body_contains: auto_tagging.body_contains)
|
||||
|
||||
posts.each do |post|
|
||||
post_repo.tag_post(post_id: post.id,
|
||||
tag_id: auto_tagging.tag_id)
|
||||
end
|
||||
end
|
||||
|
||||
Success()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
22
slices/admin/entities/auto_tagging.rb
Normal file
22
slices/admin/entities/auto_tagging.rb
Normal file
@@ -0,0 +1,22 @@
|
||||
module Admin
|
||||
module Entities
|
||||
class AutoTagging < Dry::Struct
|
||||
attribute :id, Types::Coercible::Integer
|
||||
attribute? :title_contains, Types::Optional::String
|
||||
attribute? :body_contains, Types::Optional::String
|
||||
attribute :tag_id, Types::Coercible::Integer
|
||||
|
||||
def title_only?
|
||||
!title_contains.empty?
|
||||
end
|
||||
|
||||
def term
|
||||
title_only? ? title_contains : body_contains
|
||||
end
|
||||
|
||||
class WithTag < AutoTagging
|
||||
attribute :tag, Types::Tag
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
33
slices/admin/repos/auto_tagging_repo.rb
Normal file
33
slices/admin/repos/auto_tagging_repo.rb
Normal file
@@ -0,0 +1,33 @@
|
||||
module Admin
|
||||
module Repos
|
||||
class AutoTaggingRepo < Adamantium::Repo[:auto_taggings]
|
||||
commands :create
|
||||
|
||||
def find(id)
|
||||
auto_taggings
|
||||
.where(id: id)
|
||||
.map_to(Admin::Entities::AutoTagging)
|
||||
.to_a
|
||||
end
|
||||
|
||||
def all
|
||||
auto_taggings
|
||||
.map_to(Admin::Entities::AutoTagging)
|
||||
.to_a
|
||||
end
|
||||
|
||||
def listing
|
||||
auto_taggings
|
||||
.combine(:tag)
|
||||
.map_to(Admin::Entities::AutoTagging::WithTag)
|
||||
.to_a
|
||||
end
|
||||
|
||||
def delete(id:)
|
||||
auto_taggings
|
||||
.where(id: id)
|
||||
.delete
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
37
slices/admin/repos/post_repo.rb
Normal file
37
slices/admin/repos/post_repo.rb
Normal file
@@ -0,0 +1,37 @@
|
||||
module Admin
|
||||
module Repos
|
||||
class PostRepo < Adamantium::Repo[:posts]
|
||||
def tag_post(post_id:, tag_id:)
|
||||
|
||||
return if posts
|
||||
.post_tags
|
||||
.where(
|
||||
post_id: post_id,
|
||||
tag_id: tag_id
|
||||
).count > 0
|
||||
|
||||
posts
|
||||
.post_tags
|
||||
.changeset(:create, {
|
||||
post_id: post_id,
|
||||
tag_id: tag_id
|
||||
})
|
||||
.commit
|
||||
end
|
||||
|
||||
def by_title(title_contains:)
|
||||
posts
|
||||
.where(post_type: "post")
|
||||
.published
|
||||
.where(Sequel.ilike(:name, "%#{title_contains}%")).to_a
|
||||
end
|
||||
|
||||
def by_content(body_contains:)
|
||||
posts
|
||||
.where(post_type: "post")
|
||||
.published
|
||||
.where(Sequel.ilike(:content, "%#{body_contains}%")).to_a
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@@ -5,7 +5,6 @@ module Admin
|
||||
def delete(tag_id:)
|
||||
post_tags.where(tag_id: tag_id).delete
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@@ -2,6 +2,11 @@ module Admin
|
||||
module Repos
|
||||
class TagRepo < Adamantium::Repo[:tags]
|
||||
def list
|
||||
tags
|
||||
.order(Sequel.function(:lower, :label))
|
||||
.to_a
|
||||
end
|
||||
def list_with_posts
|
||||
tags
|
||||
.combine(:posts)
|
||||
.order(Sequel.function(:lower, :label))
|
||||
|
10
slices/admin/templates/auto_tagging/index.html.slim
Normal file
10
slices/admin/templates/auto_tagging/index.html.slim
Normal file
@@ -0,0 +1,10 @@
|
||||
div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200"
|
||||
h1 Admin // Auto tagging
|
||||
|
||||
div class="prose dark:prose-invert max-w-prose mx-auto"
|
||||
- auto_taggings.each do |auto_tagging|
|
||||
div id="auto-tag-#{auto_tagging.id}"
|
||||
== "Tag post with <strong>#{auto_tagging.tag.label}</strong> when <strong>#{auto_tagging.title_only? ? "title" : "content"}</strong> contains <strong>#{auto_tagging.term}</strong>"
|
||||
= " — "
|
||||
button hx-delete="/admin/tags/auto_taggings/#{auto_tagging.id}" hx-target="#auto-tag-#{auto_tagging.id}" delete
|
||||
div class="max-w-screen-md mx-auto border-t-4 border-solid border-gray-400 dark:border-gray-600"
|
23
slices/admin/templates/auto_tagging/new.html.slim
Normal file
23
slices/admin/templates/auto_tagging/new.html.slim
Normal file
@@ -0,0 +1,23 @@
|
||||
div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200"
|
||||
h1 Admin // Auto tagging
|
||||
|
||||
div class="max-w-prose mx-auto"
|
||||
form method="POST" action="/admin/tags/auto_tagging"
|
||||
div class="mb-4"
|
||||
label class="text-gray-800 dark:text-gray-200" for="title_contains" Title contains:
|
||||
input class="text-gray-800 p-1" type="text" id="title_contains" name="title_contains"
|
||||
|
||||
div class="mb-4"
|
||||
label class="text-gray-800 dark:text-gray-200" for="body_contains" ... or body contains:
|
||||
input class="text-gray-800 p-1" type="text" id="body_contains" name="body_contains"
|
||||
|
||||
div class="mb-4"
|
||||
label class="text-gray-800 dark:text-gray-200" for="tags" Tag with:
|
||||
select class="text-gray-800" id="tags" name="tag_id"
|
||||
- tags.each do |tag|
|
||||
option value=tag.id
|
||||
= tag.label
|
||||
div class="mb-4"
|
||||
button class="rounded bg-blue-100 hover:bg-blue-200 text-blue-600 px-2 hover:cursor-pointer" type="submit"
|
||||
= "Create"
|
||||
div class="max-w-screen-md mx-auto border-t-4 border-solid border-gray-400 dark:border-gray-600"
|
13
slices/admin/types.rb
Normal file
13
slices/admin/types.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "dry/types"
|
||||
|
||||
module Admin
|
||||
Types = Dry.Types
|
||||
|
||||
module Types
|
||||
class Tag < Dry::Struct
|
||||
attribute :label, Types::Coercible::String
|
||||
end
|
||||
end
|
||||
end
|
14
slices/admin/views/auto_tagging/index.rb
Normal file
14
slices/admin/views/auto_tagging/index.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
module Admin
|
||||
module Views
|
||||
module AutoTagging
|
||||
class Index < Admin::View
|
||||
|
||||
include Deps["repos.auto_tagging_repo"]
|
||||
|
||||
expose :auto_taggings do
|
||||
auto_tagging_repo.listing
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
14
slices/admin/views/auto_tagging/new.rb
Normal file
14
slices/admin/views/auto_tagging/new.rb
Normal file
@@ -0,0 +1,14 @@
|
||||
module Admin
|
||||
module Views
|
||||
module AutoTagging
|
||||
class New < Admin::View
|
||||
|
||||
include Deps["repos.tag_repo"]
|
||||
|
||||
expose :tags do
|
||||
tag_repo.list.to_a
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@@ -6,7 +6,7 @@ module Admin
|
||||
include Deps["repos.tag_repo"]
|
||||
|
||||
expose :tags do
|
||||
tag_repo.list.to_a
|
||||
tag_repo.list_with_posts.to_a
|
||||
end
|
||||
|
||||
expose :unused_tags do |tags|
|
||||
|
Reference in New Issue
Block a user