refactor micropub_handler

This commit is contained in:
Inhji 2023-07-17 20:22:58 +02:00
parent b261dd7193
commit 45e3fc7b68
3 changed files with 147 additions and 108 deletions

View file

@ -0,0 +1,117 @@
defmodule ChiyaWeb.Indie.Micropub do
require Logger
alias ChiyaWeb.Indie.Properties, as: Props
alias ChiyaWeb.Indie.Token
def create_note(type, properties, channel_id) do
with {:ok, post_type} <- Props.get_post_type(properties),
{:ok, note_attrs} <- get_attrs(type, post_type, properties, channel_id),
{:ok, note} <- Chiya.Notes.create_note(note_attrs) do
Logger.info("Note created!")
# TODO: Make separate function for this
note_attrs
|> Props.get_photos()
|> Enum.map(fn photo ->
Chiya.Notes.create_note_image(%{
note_id: note.id,
path: photo.path
})
end)
|> Enum.each(fn result ->
Logger.info("Photo created!")
Logger.info(inspect(result))
end)
{:ok, :created, Chiya.Notes.Note.note_url(note)}
else
error ->
Logger.error("Error occurred while creating note from micropub:")
Logger.error(inspect(error))
{:error, :invalid_request}
end
end
def verify_token(access_token) do
Enum.reduce_while(
[
&verify_app_token/1,
&verify_micropub_token/1
],
nil,
fn fun, _result ->
case fun.(access_token) do
:ok -> {:halt, :ok}
error -> {:cont, error}
end
end
)
end
defp get_attrs(type, post_type, properties, default_channel_id) do
Logger.info("Creating a #{type}/#{post_type}..")
channel =
if default_channel_id,
do: Chiya.Channels.get_channel(default_channel_id),
else: nil
case post_type do
:note -> get_note_attrs(properties, channel)
_ -> {:error, :insufficient_scope}
end
end
defp verify_micropub_token(access_token) do
Token.verify(access_token, "create", get_hostname())
end
defp verify_app_token(access_token) do
token = Chiya.Accounts.get_app_token("obsidian", "app")
if not is_nil(token) do
token_string =
token.token
|> :crypto.bytes_to_integer()
|> to_string()
if token_string == access_token do
:ok
else
{:error, :insufficient_scope, "Could not verify app token"}
end
else
{:error, :insufficient_scope, "Could not verify app token"}
end
end
defp get_note_attrs(p, default_channel) do
content = Props.get_content(p)
name = Props.get_title(p) || Chiya.Notes.Note.note_title(content)
tags = Props.get_tags(p) |> Enum.join(",")
published_at =
if Props.is_published?(p),
do: NaiveDateTime.local_now(),
else: nil
attrs = %{
content: content,
name: name,
tags_string: tags,
published_at: published_at
}
attrs =
if default_channel,
do: Map.put(attrs, :channel, default_channel),
else: attrs
{:ok, attrs}
end
defp get_hostname(),
do: URI.parse(ChiyaWeb.Endpoint.url()).host
end

View file

@ -6,8 +6,7 @@ defmodule ChiyaWeb.Indie.MicropubHandler do
endpoint: ChiyaWeb.Endpoint,
router: ChiyaWeb.Router
alias ChiyaWeb.Indie.Properties, as: Props
alias ChiyaWeb.Indie.Token
alias ChiyaWeb.Indie.Micropub
@default_properties [
"name",
@ -25,35 +24,11 @@ defmodule ChiyaWeb.Indie.MicropubHandler do
Logger.info("Type: #{type}")
settings = Chiya.Site.get_settings()
micropub_channel_id = settings.micropub_channel_id
channel_id = settings.micropub_channel_id
with :ok <- verify_token(access_token),
{:ok, post_type} <- Props.get_post_type(properties),
{:ok, note_attrs} <- get_attrs(type, post_type, properties, micropub_channel_id),
{:ok, note} <- Chiya.Notes.create_note(note_attrs) do
Logger.info("Note created!")
# TODO: Make separate function for this
note_attrs
|> Props.get_photos()
|> Enum.map(fn photo ->
Chiya.Notes.create_note_image(%{
note_id: note.id,
path: photo.path
})
end)
|> Enum.each(fn result ->
Logger.info("Photo created!")
Logger.info(inspect(result))
end)
{:ok, :created, Chiya.Notes.Note.note_url(note)}
else
error ->
Logger.error("Error occurred while creating note from micropub:")
Logger.error(inspect(error))
{:error, :invalid_request}
case Micropub.verify_token(access_token) do
:ok -> Micropub.create_note(type, properties, channel_id)
_ -> {:error, :invalid_request}
end
end
@ -74,9 +49,9 @@ defmodule ChiyaWeb.Indie.MicropubHandler do
@impl true
def handle_media(file, access_token) do
with :ok <- verify_token(access_token),
with :ok <- Micropub.verify_token(access_token),
{:ok, image} <- Chiya.Notes.create_note_image_temp(%{path: file.path}) do
url = ChiyaWeb.Uploaders.UserImageTemp.url({image.path, image}, :original)
url = ChiyaWeb.Uploaders.NoteImageTemp.url({image.path, image}, :original)
{:ok, url}
else
_ ->
@ -91,7 +66,7 @@ defmodule ChiyaWeb.Indie.MicropubHandler do
do: @default_properties,
else: filter_properties
with :ok <- verify_token(access_token),
with :ok <- Micropub.verify_token(access_token),
{:ok, slug} <- Chiya.Notes.Note.note_slug(url),
note <- Chiya.Notes.get_public_note_by_slug_preloaded!(slug) do
filtered_note =
@ -107,7 +82,7 @@ defmodule ChiyaWeb.Indie.MicropubHandler do
@impl true
def handle_config_query(access_token) do
case verify_token(access_token) do
case Micropub.verify_token(access_token) do
:ok ->
channels = Chiya.Channels.list_channels()
@ -138,7 +113,7 @@ defmodule ChiyaWeb.Indie.MicropubHandler do
@impl true
def handle_syndicate_to_query(access_token) do
case verify_token(access_token) do
case Micropub.verify_token(access_token) do
:ok -> {:ok, %{"syndicate-to" => []}}
_ -> {:error, :insufficient_scope}
end
@ -146,7 +121,7 @@ defmodule ChiyaWeb.Indie.MicropubHandler do
@impl true
def handle_category_query(access_token) do
case verify_token(access_token) do
case Micropub.verify_token(access_token) do
:ok ->
tags = Enum.map(Chiya.Tags.list_tags(), fn t -> t.name end)
{:ok, %{"categories" => tags}}
@ -154,76 +129,5 @@ defmodule ChiyaWeb.Indie.MicropubHandler do
_ ->
{:error, :insufficient_scope}
end
end
defp verify_token(access_token) do
Enum.reduce_while([&verify_app_token/1, &verify_micropub_token/1], nil, fn fun, _result ->
case fun.(access_token) do
:ok -> {:halt, :ok}
error -> {:cont, error}
end
end)
end
defp verify_micropub_token(access_token) do
Token.verify(access_token, "create", get_hostname())
end
defp verify_app_token(access_token) do
token = Chiya.Accounts.get_app_token("obsidian", "app")
if not is_nil(token) do
token_string =
token.token
|> :crypto.bytes_to_integer()
|> to_string()
if token_string == access_token do
:ok
else
{:error, :insufficient_scope, "Could not verify app token"}
end
else
{:error, :insufficient_scope, "Could not verify app token"}
end
end
defp get_attrs(type, post_type, properties, default_channel_id) do
Logger.info("Creating a #{type}/#{post_type}..")
channel = Chiya.Channels.get_channel(default_channel_id)
case post_type do
:note -> get_note_attrs(properties, channel)
_ -> {:error, :insufficient_scope}
end
end
defp get_note_attrs(p, default_channel) do
content = Props.get_content(p)
name = Props.get_title(p) || Chiya.Notes.Note.note_title(content)
tags = Props.get_tags(p) |> Enum.join(",")
published_at =
if Props.is_published?(p),
do: NaiveDateTime.local_now(),
else: nil
attrs = %{
content: content,
name: name,
tags_string: tags,
published_at: published_at
}
attrs =
if default_channel,
do: Map.put(attrs, :channel, default_channel),
else: attrs
{:ok, attrs}
end
defp get_hostname(),
do: URI.parse(ChiyaWeb.Endpoint.url()).host
end
end

View file

@ -0,0 +1,18 @@
defmodule ChiyaWeb.MicropubTest do
use Chiya.DataCase
alias ChiyaWeb.Indie.Micropub
@valid_props %{
"content" => ["this is a test"]
}
describe "create_note/3" do
test "creates a note with valid attributes" do
assert {:ok, :created, url} =
Micropub.create_note("entry", @valid_props, nil)
assert url =~ "this-is-a-test"
end
end
end