devel #213
3 changed files with 147 additions and 108 deletions
117
lib/chiya_web/indie/micropub.ex
Normal file
117
lib/chiya_web/indie/micropub.ex
Normal 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
|
|
@ -6,8 +6,7 @@ defmodule ChiyaWeb.Indie.MicropubHandler do
|
||||||
endpoint: ChiyaWeb.Endpoint,
|
endpoint: ChiyaWeb.Endpoint,
|
||||||
router: ChiyaWeb.Router
|
router: ChiyaWeb.Router
|
||||||
|
|
||||||
alias ChiyaWeb.Indie.Properties, as: Props
|
alias ChiyaWeb.Indie.Micropub
|
||||||
alias ChiyaWeb.Indie.Token
|
|
||||||
|
|
||||||
@default_properties [
|
@default_properties [
|
||||||
"name",
|
"name",
|
||||||
|
@ -25,35 +24,11 @@ defmodule ChiyaWeb.Indie.MicropubHandler do
|
||||||
Logger.info("Type: #{type}")
|
Logger.info("Type: #{type}")
|
||||||
|
|
||||||
settings = Chiya.Site.get_settings()
|
settings = Chiya.Site.get_settings()
|
||||||
micropub_channel_id = settings.micropub_channel_id
|
channel_id = settings.micropub_channel_id
|
||||||
|
|
||||||
with :ok <- verify_token(access_token),
|
case Micropub.verify_token(access_token) do
|
||||||
{:ok, post_type} <- Props.get_post_type(properties),
|
:ok -> Micropub.create_note(type, properties, channel_id)
|
||||||
{:ok, note_attrs} <- get_attrs(type, post_type, properties, micropub_channel_id),
|
_ -> {:error, :invalid_request}
|
||||||
{: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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -74,9 +49,9 @@ defmodule ChiyaWeb.Indie.MicropubHandler do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_media(file, access_token) do
|
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
|
{: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}
|
{:ok, url}
|
||||||
else
|
else
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -91,7 +66,7 @@ defmodule ChiyaWeb.Indie.MicropubHandler do
|
||||||
do: @default_properties,
|
do: @default_properties,
|
||||||
else: filter_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),
|
{:ok, slug} <- Chiya.Notes.Note.note_slug(url),
|
||||||
note <- Chiya.Notes.get_public_note_by_slug_preloaded!(slug) do
|
note <- Chiya.Notes.get_public_note_by_slug_preloaded!(slug) do
|
||||||
filtered_note =
|
filtered_note =
|
||||||
|
@ -107,7 +82,7 @@ defmodule ChiyaWeb.Indie.MicropubHandler do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_config_query(access_token) do
|
def handle_config_query(access_token) do
|
||||||
case verify_token(access_token) do
|
case Micropub.verify_token(access_token) do
|
||||||
:ok ->
|
:ok ->
|
||||||
channels = Chiya.Channels.list_channels()
|
channels = Chiya.Channels.list_channels()
|
||||||
|
|
||||||
|
@ -138,7 +113,7 @@ defmodule ChiyaWeb.Indie.MicropubHandler do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_syndicate_to_query(access_token) do
|
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" => []}}
|
:ok -> {:ok, %{"syndicate-to" => []}}
|
||||||
_ -> {:error, :insufficient_scope}
|
_ -> {:error, :insufficient_scope}
|
||||||
end
|
end
|
||||||
|
@ -146,7 +121,7 @@ defmodule ChiyaWeb.Indie.MicropubHandler do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_category_query(access_token) do
|
def handle_category_query(access_token) do
|
||||||
case verify_token(access_token) do
|
case Micropub.verify_token(access_token) do
|
||||||
:ok ->
|
:ok ->
|
||||||
tags = Enum.map(Chiya.Tags.list_tags(), fn t -> t.name end)
|
tags = Enum.map(Chiya.Tags.list_tags(), fn t -> t.name end)
|
||||||
{:ok, %{"categories" => tags}}
|
{:ok, %{"categories" => tags}}
|
||||||
|
@ -155,75 +130,4 @@ defmodule ChiyaWeb.Indie.MicropubHandler do
|
||||||
{:error, :insufficient_scope}
|
{:error, :insufficient_scope}
|
||||||
end
|
end
|
||||||
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
|
||||||
|
|
18
test/chiya_web/indie/micropub_test.exs
Normal file
18
test/chiya_web/indie/micropub_test.exs
Normal 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
|
Loading…
Reference in a new issue