Packages
indieweb
0.0.5
0.0.66
0.0.65
0.0.64
0.0.63
0.0.62
0.0.61
0.0.60
0.0.59
0.0.58
0.0.56
0.0.55
0.0.54
0.0.53
0.0.51
0.0.50
0.0.49
0.0.48
0.0.47
0.0.46
0.0.42
0.0.41
0.0.40
0.0.39
0.0.38
0.0.37
0.0.36
0.0.35
0.0.34
0.0.33
0.0.32
0.0.31
0.0.30
0.0.29
0.0.28
0.0.27
0.0.26
0.0.25
0.0.24
0.0.23
0.0.22
0.0.21
0.0.20
0.0.19
0.0.17
0.0.16
0.0.15
0.0.14
0.0.13
0.0.12
0.0.10
0.0.9
0.0.8
0.0.7
0.0.6
0.0.5
0.0.3
0.0.2
0.0.1
Collection of common IndieWeb utilites like authorship resolution, Webmention, post type discovery and IndieAuth.
Current section
Files
Jump to
Current section
Files
lib/indieweb/post.ex
defmodule IndieWeb.Post do
@moduledoc """
Post-specific logic for the IndieWeb.
This module provides helper methods for parsing [MF2](http://microformats.org/wiki/microformats2-parsing)
data in a handy and simple fashion. The structure of the properties you'd use would be similar
to that of a <abbr tittle="Micformats2 JSON">MF2+JSON</abbr> object:
```json
{
"items": [
{
"type": [
"h-feed"
],
"properties": {
"name": [
"Updates"
],
"uid": [
"https://v2.jacky.wtf/stream"
],
"url": [
"https://v2.jacky.wtf/stream"
]
},
"lang": "en",
"children": [
{
"type": [
"h-entry"
],
"properties": {
"summary": [
"One big step for Koype is going to be bridging the IndieWeb into the IPFS landscape. I have concerns over it not being privacy-centric since there\u2019s no sense of private data (everything is publishable outwards). IPFS provides pubsub logic so I thi..."
],
"url": [
"https://v2.jacky.wtf/post/4fbdcd28-b558-42bc-99a9-802e33d01810",
"https://v2.jacky.wtf/tag/7c1e5ef9-aa31-40e6-b26a-ecdba728b4a1",
"https://v2.jacky.wtf/tag/bc945dde-95bb-468e-9127-620f1c35cd70"
],
"uid": [
"https://v2.jacky.wtf/post/4fbdcd28-b558-42bc-99a9-802e33d01810"
],
"category": [
"https://v2.jacky.wtf/tag/7c1e5ef9-aa31-40e6-b26a-ecdba728b4a1",
"https://v2.jacky.wtf/tag/bc945dde-95bb-468e-9127-620f1c35cd70"
],
"published": [
"2019-02-15T13:29:51.60956-08:00"
]
},
"lang": "en"
}
]
},
{
"type": [
"h-card"
],
"properties": {
"name": [
"Jacky Alcine"
],
"tz": [
"America/Los_Angeles"
],
"note": [
"I had a dream I could buy my way into heaven. When I woke up, I spent that on a m4.large from EvilCorp. Wait until I get my money right!"
],
"url": [
"https://v2.jacky.wtf"
],
"photo": [
"https://v2.jacky.wtf/media/image/floating/PhotoJacky%20n%203J5430.png?v=original"
]
},
"lang": "en"
}
]
}
```
"""
@properties_to_kind %{
"checkin" => :checkin,
"audio" => :audio,
"in-reply-to" => :reply,
"in_reply_to" => :reply,
"like-of" => :like,
"like_of" => :like,
"bookmark-of" => :bookmark,
"bookmark_of" => :bookmark,
"photo" => :photo,
"repost-of" => :repost,
"repost_of" => :repost,
"rsvp" => :rsvp,
"video" => :video,
"start" => :event,
"name" => :article
}
@doc """
Determines the type of a post from a set of types and its MF2 properties.
This aims to apply the [Post Type Discovery](http://ptd.spec.indieweb.org/) algorithm for discovering
what kind of post these properties result in.
## Examples
iex> IndieWeb.Post.determine_type(%{"content" => %{"value" => ["Foo."]}, "name" => ["Foo."]}, ~w(note article)a)
:note
iex> IndieWeb.Post.determine_type(%{"content" => %{"value" => ["Foo."]}, "name" => ["On Bar"]}, ~w(note article)a)
:article
iex> IndieWeb.Post.determine_type(%{"content" => %{"value" => ["Foo."]}, "photo" => ["https://magic/jpeg"]}, ~w(note photo)a)
:photo
"""
@doc since: "http://ptd.spec.indieweb.org/#changes-from-28-october-2016-wd-to-1-march-2017-wd"
@spec determine_type(map(), list()) :: atom()
def determine_type(properties, types) do
cond do
:event in types ->
:event
:rsvp in types ->
:rsvp
:reply in types ->
:reply
:checkin in types ->
:checkin
:repost in types ->
:repost
:bookmark in types ->
:bookmark
:like in types ->
:like
:photo in types ->
:photo
:video in types ->
:video
do_detect_note(properties) == true ->
:note
do_detect_article(properties) == true ->
:article
true ->
:note
end
end
@doc """
Determines the potential types exposed by the set of provided properties.
The provided properties are scanned and checked to determine if a particular
post type can be determined. The matching is a direct property to type mapping.
You should use `determine_type/2` to resolve the _actual_ post type.
## Examples
iex> IndieWeb.Post.extract_types(%{"photo" => ["https://magic/jpeg"]})
[:photo]
iex> IndieWeb.Post.extract_types(%{"content" => %{"value" => ["Just a note."]}})
[:note]
iex> IndieWeb.Post.extract_types(%{"content" => %{"value" => ["A whole blog post."]}, "name" => ["Magic."]})
[:article]
"""
@spec extract_types(map()) :: list()
def extract_types(properties) do
property_names =
properties
|> Map.keys()
|> Enum.map(fn
key when is_binary(key) -> key
key -> to_string(key)
end)
types =
Enum.map(property_names,&(Map.get(@properties_to_kind, &1, nil)))
|> Enum.reject(&is_nil/1)
if types == [] do
[:note]
else
types
end
end
defp do_detect_note(properties) do
cond do
Map.has_key?(properties, "name") == true -> false
String.trim(Enum.join(Map.get(properties, "name", []))) != "" -> false
true -> true
end
end
defp do_detect_article(properties) do
content = cond do
properties["content"]["value"] != [] -> properties["content"]["value"]
properties["summary"]["value"] != [] -> properties["summary"]["value"]
end
name = Map.get(properties, "name", []) |> Enum.map(&String.trim/1) |> Enum.join(" ")
!List.starts_with?(content, [name]) and name != ""
end
end