Merge branch 'markdown'

This commit is contained in:
Luna D 2021-09-21 18:25:24 +02:00
commit 625c0e4556
No known key found for this signature in database
GPG key ID: 81AF416F2CC36FC8
59 changed files with 2277 additions and 169 deletions

View file

@ -16,9 +16,7 @@ jobs:
key: ${{ runner.os }}-build-deps-${{ hashFiles('mix.lock') }} key: ${{ runner.os }}-build-deps-${{ hashFiles('mix.lock') }}
- run: docker-compose pull - run: docker-compose pull
- run: docker-compose build
- uses: satackey/action-docker-layer-caching@v0.0.8
continue-on-error: true
- name: Build and test - name: Build and test
run: docker-compose run app run-test run: docker-compose run app run-test
@ -27,8 +25,3 @@ jobs:
run: | run: |
docker-compose run app mix sobelow --config docker-compose run app mix sobelow --config
docker-compose run app mix deps.audit docker-compose run app mix deps.audit
- name: Fix permissions
run: |
sudo chown -R $(whoami):$(id -ng) deps
sudo chown -R $(whoami):$(id -ng) _build

6
.gitignore vendored
View file

@ -47,3 +47,9 @@ npm-debug.log
# Sobelow # Sobelow
.sobelow .sobelow
# Unportable compiled binaries
/priv/native/
# Rust binaries
/native/**/target

View file

@ -210,6 +210,20 @@ blockquote {
background-color: inherit; background-color: inherit;
} }
// Prevent blockquote from gaining far too much indentation and breaking.
blockquote blockquote blockquote blockquote blockquote blockquote {
margin: 1em 0;
padding: 1em 2px;
}
// Horizontal space is at a high premium on mobile.
@media (max-width: $min_px_width_for_desktop_layout) {
blockquote {
margin: 1em 4px;
padding: 1em 4px;
}
}
.spoiler { .spoiler {
background-color: $admin_links_hover_color; background-color: $admin_links_hover_color;
color: $admin_links_hover_color; color: $admin_links_hover_color;
@ -267,6 +281,26 @@ blockquote {
margin-bottom: 6px; margin-bottom: 6px;
} }
img[alt=tiny] {
max-height: $image_tiny_size;
max-width: $image_tiny_size;
}
img[alt=small] {
max-height: $image_small_size;
max-width: $image_small_size;
}
img[alt=medium] {
max-height: $image_medium_size;
max-width: $image_medium_size;
}
img[alt=large] {
max-height: $image_large_size;
max-width: $image_large_size;
}
//donations //donations
.donate-button { .donate-button {
background: 0; background: 0;

View file

@ -16,6 +16,11 @@ $medium_layout_width: 1330px;
$centered_layout_side_margin: 24px; $centered_layout_side_margin: 24px;
$layout_side_margin: 12px; $layout_side_margin: 12px;
$image_tiny_size: 64px;
$image_small_size: 128px;
$image_medium_size: 256px;
$image_large_size: 512px;
$header_height: 36px; $header_height: 36px;
$header_field_height: 28px; $header_field_height: 28px;
$header_sub_height: 32px; $header_sub_height: 32px;

View file

@ -36,6 +36,11 @@ config :philomena, PhilomenaWeb.Endpoint,
render_errors: [view: PhilomenaWeb.ErrorView, accepts: ~w(html json)], render_errors: [view: PhilomenaWeb.ErrorView, accepts: ~w(html json)],
pubsub_server: Philomena.PubSub pubsub_server: Philomena.PubSub
# Markdown
config :philomena, Philomena.Native,
crate: "philomena",
mode: :release
config :phoenix, :template_engines, config :phoenix, :template_engines,
slim: PhoenixSlime.Engine, slim: PhoenixSlime.Engine,
slime: PhoenixSlime.Engine, slime: PhoenixSlime.Engine,

View file

@ -1,7 +1,7 @@
FROM elixir:1.12.0-alpine FROM elixir:1.12.0-alpine
RUN apk update \ RUN apk update \
&& apk add inotify-tools build-base git ffmpeg ffmpeg-dev npm nodejs file-dev libpng-dev gifsicle optipng libjpeg-turbo-utils librsvg imagemagick postgresql-client wget \ && apk add inotify-tools build-base git ffmpeg ffmpeg-dev npm nodejs file-dev libpng-dev gifsicle optipng libjpeg-turbo-utils librsvg imagemagick postgresql-client wget rust cargo \
&& mix local.hex --force \ && mix local.hex --force \
&& mix local.rebar --force && mix local.rebar --force
@ -19,4 +19,5 @@ COPY docker/app/run-development /usr/local/bin/run-development
COPY docker/app/run-test /usr/local/bin/run-test COPY docker/app/run-test /usr/local/bin/run-test
COPY docker/app/safe-rsvg-convert /usr/local/bin/safe-rsvg-convert COPY docker/app/safe-rsvg-convert /usr/local/bin/safe-rsvg-convert
COPY docker/app/purge-cache /usr/local/bin/purge-cache COPY docker/app/purge-cache /usr/local/bin/purge-cache
ENV PATH=$PATH:/root/.cargo/bin
CMD run-development CMD run-development

View file

@ -1,5 +1,8 @@
#!/usr/bin/env sh #!/usr/bin/env sh
# For compatibility with musl libc
export CARGO_FEATURE_DISABLE_INITIAL_EXEC_TLS=1
background() { background() {
while :; do while :; do
mix run -e 'Philomena.Release.update_channels()' mix run -e 'Philomena.Release.update_channels()'

View file

@ -1,39 +1,3 @@
defmodule Camo.Image do defmodule Camo.Image do
def image_url(input) do def image_url(input), do: Philomena.Native.camo_image_url(input)
uri = URI.parse(input)
cond do
is_nil(uri.host) ->
""
is_nil(camo_key()) ->
input
uri.host in [cdn_host(), camo_host()] ->
URI.to_string(%{uri | scheme: "https", port: 443})
true ->
camo_digest = :crypto.mac(:hmac, :sha, camo_key(), input) |> Base.url_encode64(padding: false)
camo_uri = %URI{
host: camo_host(),
path: "/" <> camo_digest <> "/" <> Base.url_encode64(input, padding: false),
scheme: "https"
}
URI.to_string(camo_uri)
end
end
defp cdn_host do
Application.get_env(:philomena, :cdn_host)
end
defp camo_key do
Application.get_env(:philomena, :camo_key)
end
defp camo_host do
Application.get_env(:philomena, :camo_host)
end
end end

View file

@ -5,6 +5,7 @@ defmodule Philomena.Badges.Badge do
schema "badges" do schema "badges" do
field :title, :string field :title, :string
field :description, :string, default: "" field :description, :string, default: ""
field :description_md, :string, default: ""
field :image, :string field :image, :string
field :disable_award, :boolean, default: false field :disable_award, :boolean, default: false
field :priority, :boolean, default: false field :priority, :boolean, default: false

View file

@ -14,6 +14,7 @@ defmodule Philomena.Channels.Channel do
field :short_name, :string field :short_name, :string
field :title, :string, default: "" field :title, :string, default: ""
field :description, :string field :description, :string
field :description_md, :string
field :tags, :string field :tags, :string
field :viewers, :integer, default: 0 field :viewers, :integer, default: 0
field :nsfw, :boolean, default: false field :nsfw, :boolean, default: false

View file

@ -11,6 +11,7 @@ defmodule Philomena.Comments.Comment do
belongs_to :deleted_by, User belongs_to :deleted_by, User
field :body, :string field :body, :string
field :body_md, :string
field :ip, EctoNetwork.INET field :ip, EctoNetwork.INET
field :fingerprint, :string field :fingerprint, :string
field :user_agent, :string, default: "" field :user_agent, :string, default: ""

View file

@ -17,6 +17,10 @@ defmodule Philomena.Commissions.Commission do
field :contact, :string field :contact, :string
field :will_create, :string field :will_create, :string
field :will_not_create, :string field :will_not_create, :string
field :information_md, :string
field :contact_md, :string
field :will_create_md, :string
field :will_not_create_md, :string
field :commission_items_count, :integer, default: 0 field :commission_items_count, :integer, default: 0
timestamps(inserted_at: :created_at, type: :utc_datetime) timestamps(inserted_at: :created_at, type: :utc_datetime)

View file

@ -11,8 +11,10 @@ defmodule Philomena.Commissions.Item do
field :item_type, :string field :item_type, :string
field :description, :string field :description, :string
field :description_md, :string
field :base_price, :decimal field :base_price, :decimal
field :add_ons, :string field :add_ons, :string
field :add_ons_md, :string
timestamps(inserted_at: :created_at, type: :utc_datetime) timestamps(inserted_at: :created_at, type: :utc_datetime)
end end

View file

@ -10,6 +10,7 @@ defmodule Philomena.Conversations.Message do
belongs_to :from, User belongs_to :from, User
field :body, :string field :body, :string
field :body_md, :string
timestamps(inserted_at: :created_at, type: :utc_datetime) timestamps(inserted_at: :created_at, type: :utc_datetime)
end end

View file

@ -17,6 +17,9 @@ defmodule Philomena.DnpEntries.DnpEntry do
field :hide_reason, :boolean, default: false field :hide_reason, :boolean, default: false
field :instructions, :string, default: "" field :instructions, :string, default: ""
field :feedback, :string, default: "" field :feedback, :string, default: ""
field :conditions_md, :string, default: ""
field :reason_md, :string, default: ""
field :instructions_md, :string, default: ""
timestamps(inserted_at: :created_at, type: :utc_datetime) timestamps(inserted_at: :created_at, type: :utc_datetime)
end end

View file

@ -12,6 +12,7 @@ defmodule Philomena.Filters.Filter do
field :name, :string field :name, :string
field :description, :string, default: "" field :description, :string, default: ""
field :description_md, :string, default: ""
field :system, :boolean field :system, :boolean
field :public, :boolean field :public, :boolean
field :hidden_complex_str, :string field :hidden_complex_str, :string

View file

@ -17,6 +17,7 @@ defmodule Philomena.Galleries.Gallery do
field :title, :string field :title, :string
field :spoiler_warning, :string, default: "" field :spoiler_warning, :string, default: ""
field :description, :string, default: "" field :description, :string, default: ""
field :description_md, :string, default: ""
field :image_count, :integer field :image_count, :integer
field :order_position_asc, :boolean field :order_position_asc, :boolean

View file

@ -64,6 +64,7 @@ defmodule Philomena.Images.Image do
field :votes_count, :integer, default: 0 field :votes_count, :integer, default: 0
field :source_url, :string field :source_url, :string
field :description, :string, default: "" field :description, :string, default: ""
field :description_md, :string, default: ""
field :image_sha512_hash, :string field :image_sha512_hash, :string
field :image_orig_sha512_hash, :string field :image_orig_sha512_hash, :string
field :deletion_reason, :string field :deletion_reason, :string
@ -80,6 +81,7 @@ defmodule Philomena.Images.Image do
field :destroyed_content, :boolean field :destroyed_content, :boolean
field :hidden_image_key, :string field :hidden_image_key, :string
field :scratchpad, :string field :scratchpad, :string
field :scratchpad_md, :string
field :hides_count, :integer, default: 0 field :hides_count, :integer, default: 0
# todo: can probably remove these now # todo: can probably remove these now

16
lib/philomena/markdown.ex Normal file
View file

@ -0,0 +1,16 @@
defmodule Philomena.Markdown do
@markdown_chars ~r/[\*_\[\]\(\)\^`\%\\~<>#\|]/
# When your NIF is loaded, it will override this function.
def to_html(text, replacements), do: Philomena.Native.markdown_to_html(text, replacements)
def to_html_unsafe(text, replacements),
do: Philomena.Native.markdown_to_html_unsafe(text, replacements)
def escape_markdown(text) do
@markdown_chars
|> Regex.replace(text, fn m ->
"\\#{m}"
end)
end
end

View file

@ -12,6 +12,7 @@ defmodule Philomena.ModNotes.ModNote do
field :notable_type, :string field :notable_type, :string
field :body, :string field :body, :string
field :body_md, :string
field :notable, :any, virtual: true field :notable, :any, virtual: true

10
lib/philomena/native.ex Normal file
View file

@ -0,0 +1,10 @@
defmodule Philomena.Native do
use Rustler, otp_app: :philomena
# Markdown
def markdown_to_html(_text, _replacements), do: :erlang.nif_error(:nif_not_loaded)
def markdown_to_html_unsafe(_text, _replacements), do: :erlang.nif_error(:nif_not_loaded)
# Camo
def camo_image_url(_uri), do: :erlang.nif_error(:nif_not_loaded)
end

View file

@ -11,6 +11,7 @@ defmodule Philomena.Posts.Post do
belongs_to :deleted_by, User belongs_to :deleted_by, User
field :body, :string field :body, :string
field :body_md, :string
field :edit_reason, :string field :edit_reason, :string
field :ip, EctoNetwork.INET field :ip, EctoNetwork.INET
field :fingerprint, :string field :fingerprint, :string

View file

@ -13,6 +13,7 @@ defmodule Philomena.Reports.Report do
field :user_agent, :string, default: "" field :user_agent, :string, default: ""
field :referrer, :string, default: "" field :referrer, :string, default: ""
field :reason, :string field :reason, :string
field :reason_md, :string
field :state, :string, default: "open" field :state, :string, default: "open"
field :open, :boolean, default: true field :open, :boolean, default: true

View file

@ -77,6 +77,7 @@ defmodule Philomena.Tags.Tag do
field :category, :string field :category, :string
field :images_count, :integer, default: 0 field :images_count, :integer, default: 0
field :description, :string field :description, :string
field :description_md, :string
field :short_description, :string field :short_description, :string
field :namespace, :string field :namespace, :string
field :name_in_namespace, :string field :name_in_namespace, :string

View file

@ -2,9 +2,9 @@ defmodule Philomena.Textile.Lexer do
import NimbleParsec import NimbleParsec
token_list = token_list =
Enum.to_list(0x01..0x29) Enum.to_list(0x01..0x29) ++
++ Enum.to_list(0x2b..0x2f) Enum.to_list(0x2B..0x2F) ++
++ ':;<=>?[]\\^`~|' ':;<=>?[]\\^`~|'
space_list = '\f \r\t\u00a0\u1680\u180e\u202f\u205f\u3000' ++ Enum.to_list(0x2000..0x200A) space_list = '\f \r\t\u00a0\u1680\u180e\u202f\u205f\u3000' ++ Enum.to_list(0x2000..0x200A)
space = utf8_char(space_list) space = utf8_char(space_list)

View file

@ -0,0 +1,601 @@
# LUNA PRESENTS THEE
#
# DA ULTIMATE, BESTEST, MOST SECURE AND DEFINITELY NOT BUGGY
# TEXTILE TO MARKDOWN CONVERTER PARSER LIBRARY THING!!!!!
#
# IT'S SO AWESOME I HAVE TO DESCRIBE IT IN ALL CAPS
#
# BY LOOKING AT THIS SOURCE CODE YOU AGREE THAT I MAY NOT BE HELD
# RESPONSIBLE FOR YOU DEVELOPING EYE CANCER
#
# YOU'VE BEEN WARNED
#
# COPYRIGHT (C) (R) (TM) LUNA (C) (R) (TM) 2021-206969696969
defmodule Philomena.Textile.ParserMarkdown do
alias Philomena.Textile.Lexer
alias Philomena.Markdown
alias Phoenix.HTML
defp markdown_quote(text) do
result = Regexp.replace(~r/\n/, text, "\\0> ")
"> #{result}"
end
def parse(parser, input) do
parser = Map.put(parser, :state, %{})
with {:ok, tokens, _1, _2, _3, _4} <- Lexer.lex(String.trim(input || "")),
{:ok, tree, []} <- repeat(&textile/3, parser, tokens, false, 0) do
partial_flatten(tree)
else
_ ->
[]
end
end
# Helper to turn a parse tree into a string
def flatten(tree) do
tree
|> List.flatten()
|> Enum.map_join("", fn {_k, v} -> v end)
end
def flatten_unquote(tree) do
tree
|> List.flatten()
|> Enum.map_join("", fn {_k, v} ->
Regex.replace(~r/\n(> )/, v, "\n")
end)
end
# Helper to turn a parse tree into a list
def partial_flatten(tree) do
tree
|> List.flatten()
|> Enum.chunk_by(fn {k, _v} -> k end)
|> Enum.map(fn list ->
[{type, _v} | _rest] = list
value = Enum.map_join(list, "", fn {_k, v} -> v end)
{type, value}
end)
end
defp put_state(parser, new_state) do
state = Map.put(parser.state, new_state, true)
Map.put(parser, :state, state)
end
# Helper corresponding to Kleene star (*) operator
# Match a specificed rule zero or more times
defp repeat(rule, parser, tokens, bq, level) when bq == true do
case rule.(parser, tokens, true, level) do
{:ok, tree, r_tokens} ->
{:ok, tree2, r2_tokens, level} = repeat(rule, parser, r_tokens, true, level)
{:ok, [tree, tree2], r2_tokens, level}
_ ->
{:ok, [], tokens, level}
end
end
defp repeat(rule, parser, tokens, bq, level) do
case rule.(parser, tokens, level) do
{:ok, tree, r_tokens} ->
{:ok, tree2, r2_tokens} = repeat(rule, parser, r_tokens, false, level)
{:ok, [tree, tree2], r2_tokens}
_ ->
{:ok, [], tokens}
end
end
# Helper to match a simple recursive grammar rule of the following form:
#
# open_token callback* close_token
#
defp simple_recursive(
:bq_open,
:bq_close,
open_tag,
close_tag,
callback,
parser,
[
{:bq_open, open} | r_tokens
],
level
) do
case repeat(callback, parser, r_tokens, true, level) do
{:ok, tree, [{:bq_close, _} | r2_tokens], level} ->
{:ok,
[
{:markup, "\n" <> String.duplicate(open_tag, level)},
tree,
{:markup, "\n" <> String.duplicate(close_tag, level - 1)}
], r2_tokens}
{:ok, tree, r2_tokens, level} ->
{:ok, [{:text, open}, tree], r2_tokens}
end
end
defp simple_recursive(
open_token,
close_token,
open_tag,
close_tag,
callback,
parser,
[
{open_token, open} | r_tokens
],
level
) do
case repeat(callback, parser, r_tokens, false, level) do
{:ok, tree, [{^close_token, _} | r2_tokens]} ->
{:ok, [{:markup, open_tag}, tree, {:markup, close_tag}], r2_tokens}
{:ok, tree, r2_tokens} ->
{:ok, [{:text, open}, tree], r2_tokens}
end
end
defp simple_recursive(
_open_token,
_close_token,
_open_tag,
_close_tag,
_callback,
_parser,
_tokens,
_level
) do
{:error, "Expected a simple recursive rule"}
end
# Helper to match a simple recursive grammar rule with negative lookahead:
#
# open_token callback* close_token (?!lookahead_not)
#
defp simple_lookahead_not(
open_token,
close_token,
open_tag,
close_tag,
lookahead_not,
callback,
state,
parser,
[{open_token, open} | r_tokens],
level
) do
case parser.state do
%{^state => _} ->
{:error, "End of rule"}
_ ->
case r_tokens do
[{forbidden_lookahead, _la} | _] when forbidden_lookahead in [:space, :newline] ->
{:ok, [{:text, open}], r_tokens}
_ ->
case repeat(callback, put_state(parser, state), r_tokens, false, level) do
{:ok, tree, [{^close_token, close}, {^lookahead_not, ln} | r2_tokens]} ->
{:ok, [{:text, open}, tree, {:text, close}], [{lookahead_not, ln} | r2_tokens]}
{:ok, tree, [{^close_token, _} | r2_tokens]} ->
{:ok, [{:markup, open_tag}, tree, {:markup, close_tag}], r2_tokens}
{:ok, tree, r2_tokens} ->
{:ok, [{:text, open}, tree], r2_tokens}
end
end
end
end
defp simple_lookahead_not(
_open_token,
_close_token,
_open_tag,
_close_tag,
_lookahead_not,
_callback,
_state,
_parser,
_tokens,
_level
) do
{:error, "Expected a simple lookahead not rule"}
end
# Helper to efficiently assemble a UTF-8 binary from tokens of the
# given type
defp assemble_binary(token_type, accumulator, [{token_type, t} | stream]) do
assemble_binary(token_type, accumulator <> <<t::utf8>>, stream)
end
defp assemble_binary(_token_type, accumulator, tokens), do: {accumulator, tokens}
#
# inline_textile_element =
# opening_markup inline_textile_element* closing_markup (?!quicktxt) |
# closing_markup (?=quicktxt) |
# link_delim block_textile_element* link_url |
# image url? |
# code_delim inline_textile_element* code_delim |
# inline_textile_element_not_opening_markup;
#
defp inline_textile_element(parser, tokens, level) do
[
{:b_delim, :b, "**", "**"},
{:i_delim, :i, "_", "_"},
{:strong_delim, :strong, "**", "**"},
{:em_delim, :em, "*", "*"},
{:ins_delim, :ins, "__", "__"},
{:sup_delim, :sup, "^", "^"},
{:del_delim, :del, "~~", "~~"},
{:sub_delim, :sub, "%", "%"}
]
|> Enum.find_value(fn {delim_token, state, open_tag, close_tag} ->
simple_lookahead_not(
delim_token,
delim_token,
open_tag,
close_tag,
:quicktxt,
&inline_textile_element/3,
state,
parser,
tokens,
level
)
|> case do
{:ok, tree, r_tokens} ->
{:ok, tree, r_tokens}
_ ->
nil
end
end)
|> case do
nil -> inner_inline_textile_element(parser, tokens, level)
value -> value
end
end
defp inner_inline_textile_element(parser, [{token, t}, {:quicktxt, q} | r_tokens], level)
when token in [
:b_delim,
:i_delim,
:strong_delim,
:em_delim,
:ins_delim,
:sup_delim,
:del_delim,
:sub_delim
] do
case inline_textile_element(parser, [{:quicktxt, q} | r_tokens], level) do
{:ok, tree, r2_tokens} ->
{:ok, [{:text, t}, tree], r2_tokens}
_ ->
{:ok, [{:text, t}], [{:quicktxt, q} | r_tokens]}
end
end
defp inner_inline_textile_element(parser, [{:link_delim, open} | r_tokens], level) do
case repeat(&block_textile_element/3, parser, r_tokens, false, level) do
{:ok, tree, [{:unbracketed_link_url, <<"\":", url::binary>>} | r2_tokens]} ->
href = url
{:ok, [{:markup, "["}, tree, {:markup, "]("}, {:markup, href}, {:markup, ")"}], r2_tokens}
{:ok, tree, r2_tokens} ->
{:ok, [{:text, open}, tree], r2_tokens}
end
end
defp inner_inline_textile_element(parser, [{:bracketed_link_open, open} | r_tokens], level) do
case repeat(&inline_textile_element/3, parser, r_tokens, false, level) do
{:ok, tree, [{:bracketed_link_url, <<"\":", url::binary>>} | r2_tokens]} ->
href = url
{:ok, [{:markup, "["}, tree, {:markup, "]("}, {:markup, href}, {:markup, ")"}], r2_tokens}
{:ok, tree, r2_tokens} ->
{:ok, [{:text, open}, tree], r2_tokens}
end
end
defp inner_inline_textile_element(
parser,
[
{token, img},
{:unbracketed_image_url, <<":", url::binary>>} | r_tokens
],
level
)
when token in [:unbracketed_image, :bracketed_image] do
img = parser.image_transform.(img)
{:ok,
[
{:markup, "[![full]("},
{:markup, img},
{:markup, ")]("},
{:markup, url},
{:markup, ")"}
], r_tokens}
end
defp inner_inline_textile_element(parser, [{token, img} | r_tokens], level)
when token in [:unbracketed_image, :bracketed_image] do
img = parser.image_transform.(img)
{:ok,
[
{:markup, "![full]("},
{:markup, img},
{:markup, ")"}
], r_tokens}
end
defp inner_inline_textile_element(parser, [{:code_delim, open} | r_tokens], level) do
case parser.state do
%{code: _} ->
{:error, "End of rule"}
_ ->
case repeat(&inline_textile_element/3, put_state(parser, :code), r_tokens, false, level) do
{:ok, tree, [{:code_delim, _} | r2_tokens]} ->
{:ok, [{:markup, "`"}, tree, {:markup, "`"}], r2_tokens}
{:ok, tree, r2_tokens} ->
{:ok, [{:text, open}, tree], r2_tokens}
end
end
end
defp inner_inline_textile_element(parser, tokens, level \\ 0) do
inline_textile_element_not_opening_markup(parser, tokens, level)
end
#
# bq_cite_text = (?!bq_cite_open);
#
# Note that text is not escaped here because it will be escaped
# when the tree is flattened
defp bq_cite_text(_parser, [{:bq_cite_open, _open} | _rest], level) do
{:error, "Expected cite tokens"}
end
defp bq_cite_text(_parser, [{:char, lit} | r_tokens], level) do
{:ok, [{:text, <<lit::utf8>>}], r_tokens}
end
defp bq_cite_text(_parser, [{:quicktxt, lit} | r_tokens], level) do
{:ok, [{:text, <<lit::utf8>>}], r_tokens}
end
defp bq_cite_text(_parser, [{:space, _} | r_tokens], level) do
{:ok, [{:text, " "}], r_tokens}
end
defp bq_cite_text(_parser, [{_token, t} | r_tokens], level) do
{:ok, [{:text, t}], r_tokens}
end
defp bq_cite_text(_parser, _tokens, _level) do
{:error, "Expected cite tokens"}
end
#
# inline_textile_element_not_opening_markup =
# literal | space | char |
# quicktxt opening_markup quicktxt |
# quicktxt |
# opening_block_tag block_textile_element* closing_block_tag;
#
defp inline_textile_element_not_opening_markup(_parser, [{:literal, lit} | r_tokens], level) do
{:ok, [{:markup, Markdown.escape_markdown(lit)}], r_tokens}
end
defp inline_textile_element_not_opening_markup(_parser, [{:space, _} | r_tokens], level) do
{:ok, [{:text, " "}], r_tokens}
end
defp inline_textile_element_not_opening_markup(_parser, [{:char, lit} | r_tokens], level) do
{binary, r2_tokens} = assemble_binary(:char, <<lit::utf8>>, r_tokens)
{:ok, [{:text, binary}], r2_tokens}
end
defp inline_textile_element_not_opening_markup(
_parser,
[
{:quicktxt, q1},
{token, t},
{:quicktxt, q2} | r_tokens
],
level
)
when token in [
:b_delim,
:i_delim,
:strong_delim,
:em_delim,
:ins_delim,
:sup_delim,
:del_delim,
:sub_delim
] do
{:ok, [{:text, <<q1::utf8>>}, {:text, t}, {:text, <<q2::utf8>>}], r_tokens}
end
defp inline_textile_element_not_opening_markup(_parser, [{:quicktxt, lit} | r_tokens], level) do
{:ok, [{:text, <<lit::utf8>>}], r_tokens}
end
defp inline_textile_element_not_opening_markup(
parser,
[{:bq_cite_start, start} | r_tokens],
level
) do
case repeat(&bq_cite_text/3, parser, r_tokens, false, level) do
{:ok, tree, [{:bq_cite_open, open} | r2_tokens]} ->
case repeat(&block_textile_element/4, parser, r2_tokens, true, level + 1) do
{:ok, tree2, [{:bq_close, _} | r3_tokens], level} ->
cite = flatten(tree)
{:ok,
[
{:markup, "\n" <> String.duplicate("> ", level)},
tree2,
{:markup, "\n" <> String.duplicate("> ", level - 1)}
], r3_tokens}
{:ok, tree2, r3_tokens, level} ->
{:ok,
[
{:text, start},
{:text, flatten(tree)},
{:text, open},
tree2
], r3_tokens}
end
_ ->
{:ok, [{:text, start}], r_tokens}
end
end
defp inline_textile_element_not_opening_markup(
_parser,
[{:bq_cite_open, tok} | r_tokens],
level
) do
{:ok, [{:text, tok}], r_tokens}
end
defp inline_textile_element_not_opening_markup(
parser,
[{:bq_open, start} | r_tokens],
level
) do
case repeat(&block_textile_element/4, parser, r_tokens, true, level + 1) do
{:ok, tree, [{:bq_close, _} | r2_tokens], level} ->
{:ok,
[
{:markup, "\n" <> String.duplicate("> ", level)},
tree,
{:markup, "\n" <> String.duplicate("> ", level - 1)}
], r2_tokens}
{:ok, tree, r2_tokens, level} ->
{:ok,
[
{:text, start},
{:text, flatten_unquote(tree)}
], r2_tokens}
end
end
defp inline_textile_element_not_opening_markup(
_parser,
[{:bq_open, tok} | r_tokens],
level
) do
{:ok, [{:text, tok}], r_tokens}
end
defp inline_textile_element_not_opening_markup(parser, tokens, level) do
[
{:spoiler_open, :spoiler_close, "||", "||"},
{:bracketed_b_open, :bracketed_b_close, "**", "**"},
{:bracketed_i_open, :bracketed_i_close, "_", "_"},
{:bracketed_strong_open, :bracketed_strong_close, "**", "**"},
{:bracketed_em_open, :bracketed_em_close, "*", "*"},
{:bracketed_code_open, :bracketed_code_close, "```", "```"},
{:bracketed_ins_open, :bracketed_ins_close, "__", "__"},
{:bracketed_sup_open, :bracketed_sup_close, "^", "^"},
{:bracketed_del_open, :bracketed_del_close, "~~", "~~"},
{:bracketed_sub_open, :bracketed_sub_close, "%", "%"}
]
|> Enum.find_value(fn {open_token, close_token, open_tag, close_tag} ->
simple_recursive(
open_token,
close_token,
open_tag,
close_tag,
&block_textile_element/3,
parser,
tokens,
level
)
|> case do
{:ok, tree, r_tokens} ->
{:ok, tree, r_tokens}
_ ->
nil
end
end)
|> Kernel.||({:error, "Expected block markup"})
end
#
# block_textile_element =
# double_newline | newline | inline_textile_element;
#
defp block_textile_element(_parser, [{:double_newline, _} | r_tokens], bq, level)
when bq == true do
one = "\n" <> String.duplicate("> ", level)
{:ok, [{:markup, String.duplicate(one, 2)}], r_tokens}
end
defp block_textile_element(_parser, [{:newline, _} | r_tokens], bq, level) when bq == true do
{:ok, [{:markup, "\n" <> String.duplicate("> ", level)}], r_tokens}
end
defp block_textile_element(parser, tokens, _bq, level) do
inline_textile_element(parser, tokens, level)
end
defp block_textile_element(_parser, [{:double_newline, _} | r_tokens]) do
{:ok, [{:markup, "\n\n"}], r_tokens}
end
defp block_textile_element(_parser, [{:newline, _} | r_tokens]) do
{:ok, [{:markup, "\n"}], r_tokens}
end
defp block_textile_element(parser, tokens, level) do
inline_textile_element(parser, tokens, level)
end
#
# textile =
# (block_textile_element | TOKEN)* eos;
#
defp textile(parser, tokens, level) do
case block_textile_element(parser, tokens, level) do
{:ok, tree, r_tokens} ->
{:ok, tree, r_tokens}
_ ->
case tokens do
[{_, string} | r_tokens] ->
{:ok, [{:text, string}], r_tokens}
_ ->
{:error, "Expected textile"}
end
end
end
end

View file

@ -65,6 +65,7 @@ defmodule Philomena.Users.User do
field :slug, :string field :slug, :string
field :role, :string, default: "user" field :role, :string, default: "user"
field :description, :string field :description, :string
field :description_md, :string
field :avatar, :string field :avatar, :string
# Settings # Settings
@ -115,6 +116,7 @@ defmodule Philomena.Users.User do
field :last_renamed_at, :utc_datetime field :last_renamed_at, :utc_datetime
field :deleted_at, :utc_datetime field :deleted_at, :utc_datetime
field :scratchpad, :string field :scratchpad, :string
field :scratchpad_md, :string
field :secondary_role, :string field :secondary_role, :string
field :hide_default_role, :boolean, default: false field :hide_default_role, :boolean, default: false
field :senior_staff, :boolean, default: false field :senior_staff, :boolean, default: false

View file

@ -1,7 +1,7 @@
defmodule PhilomenaWeb.Admin.DnpEntryController do defmodule PhilomenaWeb.Admin.DnpEntryController do
use PhilomenaWeb, :controller use PhilomenaWeb, :controller
alias PhilomenaWeb.TextileRenderer alias PhilomenaWeb.TextRenderer
alias Philomena.DnpEntries.DnpEntry alias Philomena.DnpEntries.DnpEntry
alias Philomena.Repo alias Philomena.Repo
import Ecto.Query import Ecto.Query
@ -44,8 +44,8 @@ defmodule PhilomenaWeb.Admin.DnpEntryController do
bodies = bodies =
dnp_entries dnp_entries
|> Enum.map(&%{body: &1.conditions}) |> Enum.map(&%{body: &1.conditions, body_md: &1.conditions_md})
|> TextileRenderer.render_collection(conn) |> TextRenderer.render_collection(conn)
dnp_entries = %{dnp_entries | entries: Enum.zip(bodies, dnp_entries.entries)} dnp_entries = %{dnp_entries | entries: Enum.zip(bodies, dnp_entries.entries)}

View file

@ -1,7 +1,7 @@
defmodule PhilomenaWeb.Admin.ModNoteController do defmodule PhilomenaWeb.Admin.ModNoteController do
use PhilomenaWeb, :controller use PhilomenaWeb, :controller
alias PhilomenaWeb.TextileRenderer alias PhilomenaWeb.TextRenderer
alias Philomena.ModNotes.ModNote alias Philomena.ModNotes.ModNote
alias Philomena.Polymorphic alias Philomena.Polymorphic
alias Philomena.ModNotes alias Philomena.ModNotes
@ -29,7 +29,7 @@ defmodule PhilomenaWeb.Admin.ModNoteController do
|> order_by(desc: :id) |> order_by(desc: :id)
|> Repo.paginate(conn.assigns.scrivener) |> Repo.paginate(conn.assigns.scrivener)
bodies = TextileRenderer.render_collection(mod_notes, conn) bodies = TextRenderer.render_collection(mod_notes, conn)
preloaded = Polymorphic.load_polymorphic(mod_notes, notable: [notable_id: :notable_type]) preloaded = Polymorphic.load_polymorphic(mod_notes, notable: [notable_id: :notable_type])
mod_notes = %{mod_notes | entries: Enum.zip(bodies, preloaded)} mod_notes = %{mod_notes | entries: Enum.zip(bodies, preloaded)}

View file

@ -2,7 +2,7 @@ defmodule PhilomenaWeb.Admin.ReportController do
use PhilomenaWeb, :controller use PhilomenaWeb, :controller
alias Philomena.Elasticsearch alias Philomena.Elasticsearch
alias PhilomenaWeb.TextileRenderer alias PhilomenaWeb.TextRenderer
alias Philomena.Reports.Report alias Philomena.Reports.Report
alias Philomena.Reports.Query alias Philomena.Reports.Query
alias Philomena.Polymorphic alias Philomena.Polymorphic
@ -73,7 +73,7 @@ defmodule PhilomenaWeb.Admin.ReportController do
reportable: [reportable_id: :reportable_type] reportable: [reportable_id: :reportable_type]
) )
body = TextileRenderer.render_one(%{body: report.reason}, conn) body = TextRenderer.render_one(%{body: report.reason, body_md: report.reason_md}, conn)
render(conn, "show.html", title: "Showing Report", report: report, body: body) render(conn, "show.html", title: "Showing Report", report: report, body: body)
end end
@ -125,7 +125,7 @@ defmodule PhilomenaWeb.Admin.ReportController do
mod_notes = mod_notes =
mod_notes mod_notes
|> TextileRenderer.render_collection(conn) |> TextRenderer.render_collection(conn)
|> Enum.zip(mod_notes) |> Enum.zip(mod_notes)
assign(conn, :mod_notes, mod_notes) assign(conn, :mod_notes, mod_notes)

View file

@ -1,7 +1,7 @@
defmodule PhilomenaWeb.CommentController do defmodule PhilomenaWeb.CommentController do
use PhilomenaWeb, :controller use PhilomenaWeb, :controller
alias PhilomenaWeb.TextileRenderer alias PhilomenaWeb.TextRenderer
alias Philomena.Elasticsearch alias Philomena.Elasticsearch
alias Philomena.{Comments.Query, Comments.Comment} alias Philomena.{Comments.Query, Comments.Comment}
import Ecto.Query import Ecto.Query
@ -39,7 +39,7 @@ defmodule PhilomenaWeb.CommentController do
preload(Comment, [:deleted_by, image: [tags: :aliases], user: [awards: :badge]]) preload(Comment, [:deleted_by, image: [tags: :aliases], user: [awards: :badge]])
) )
rendered = TextileRenderer.render_collection(comments.entries, conn) rendered = TextRenderer.render_collection(comments.entries, conn)
comments = %{comments | entries: Enum.zip(rendered, comments.entries)} comments = %{comments | entries: Enum.zip(rendered, comments.entries)}

View file

@ -3,7 +3,7 @@ defmodule PhilomenaWeb.ConversationController do
alias PhilomenaWeb.NotificationCountPlug alias PhilomenaWeb.NotificationCountPlug
alias Philomena.{Conversations, Conversations.Conversation, Conversations.Message} alias Philomena.{Conversations, Conversations.Conversation, Conversations.Message}
alias PhilomenaWeb.TextileRenderer alias PhilomenaWeb.TextRenderer
alias Philomena.Repo alias Philomena.Repo
import Ecto.Query import Ecto.Query
@ -72,7 +72,7 @@ defmodule PhilomenaWeb.ConversationController do
rendered = rendered =
messages.entries messages.entries
|> TextileRenderer.render_collection(conn) |> TextRenderer.render_collection(conn)
messages = %{messages | entries: Enum.zip(messages.entries, rendered)} messages = %{messages | entries: Enum.zip(messages.entries, rendered)}

View file

@ -2,7 +2,7 @@ defmodule PhilomenaWeb.DnpEntryController do
use PhilomenaWeb, :controller use PhilomenaWeb, :controller
alias Philomena.DnpEntries.DnpEntry alias Philomena.DnpEntries.DnpEntry
alias PhilomenaWeb.TextileRenderer alias PhilomenaWeb.TextRenderer
alias Philomena.DnpEntries alias Philomena.DnpEntries
alias Philomena.Tags.Tag alias Philomena.Tags.Tag
alias Philomena.ModNotes.ModNote alias Philomena.ModNotes.ModNote
@ -43,8 +43,8 @@ defmodule PhilomenaWeb.DnpEntryController do
bodies = bodies =
dnp_entries dnp_entries
|> Enum.map(&%{body: &1.conditions || "-"}) |> Enum.map(&%{body_md: &1.conditions_md, body: &1.conditions || "-"})
|> TextileRenderer.render_collection(conn) |> TextRenderer.render_collection(conn)
dnp_entries = %{dnp_entries | entries: Enum.zip(bodies, dnp_entries.entries)} dnp_entries = %{dnp_entries | entries: Enum.zip(bodies, dnp_entries.entries)}
@ -61,11 +61,11 @@ defmodule PhilomenaWeb.DnpEntryController do
dnp_entry = conn.assigns.dnp_entry dnp_entry = conn.assigns.dnp_entry
[conditions, reason, instructions] = [conditions, reason, instructions] =
TextileRenderer.render_collection( TextRenderer.render_collection(
[ [
%{body: dnp_entry.conditions || "-"}, %{body_md: dnp_entry.conditions_md, body: dnp_entry.conditions || "-"},
%{body: dnp_entry.reason || "-"}, %{body_md: dnp_entry.reason_md, body: dnp_entry.reason || "-"},
%{body: dnp_entry.instructions || "-"} %{body_md: dnp_entry.instructions_md, body: dnp_entry.instructions || "-"}
], ],
conn conn
) )
@ -164,7 +164,7 @@ defmodule PhilomenaWeb.DnpEntryController do
mod_notes = mod_notes =
mod_notes mod_notes
|> TextileRenderer.render_collection(conn) |> TextRenderer.render_collection(conn)
|> Enum.zip(mod_notes) |> Enum.zip(mod_notes)
assign(conn, :mod_notes, mod_notes) assign(conn, :mod_notes, mod_notes)

View file

@ -2,7 +2,7 @@ defmodule PhilomenaWeb.Image.CommentController do
use PhilomenaWeb, :controller use PhilomenaWeb, :controller
alias PhilomenaWeb.CommentLoader alias PhilomenaWeb.CommentLoader
alias PhilomenaWeb.TextileRenderer alias PhilomenaWeb.TextRenderer
alias Philomena.{Images.Image, Comments.Comment} alias Philomena.{Images.Image, Comments.Comment}
alias Philomena.UserStatistics alias Philomena.UserStatistics
alias Philomena.Comments alias Philomena.Comments
@ -48,7 +48,7 @@ defmodule PhilomenaWeb.Image.CommentController do
def index(conn, _params) do def index(conn, _params) do
comments = CommentLoader.load_comments(conn, conn.assigns.image) comments = CommentLoader.load_comments(conn, conn.assigns.image)
rendered = TextileRenderer.render_collection(comments.entries, conn) rendered = TextRenderer.render_collection(comments.entries, conn)
comments = %{comments | entries: Enum.zip(comments.entries, rendered)} comments = %{comments | entries: Enum.zip(comments.entries, rendered)}
@ -56,7 +56,7 @@ defmodule PhilomenaWeb.Image.CommentController do
end end
def show(conn, _params) do def show(conn, _params) do
rendered = TextileRenderer.render_one(conn.assigns.comment, conn) rendered = TextRenderer.render_one(conn.assigns.comment, conn)
render(conn, "show.html", render(conn, "show.html",
layout: false, layout: false,

View file

@ -1,7 +1,7 @@
defmodule PhilomenaWeb.Image.DescriptionController do defmodule PhilomenaWeb.Image.DescriptionController do
use PhilomenaWeb, :controller use PhilomenaWeb, :controller
alias PhilomenaWeb.TextileRenderer alias PhilomenaWeb.TextRenderer
alias Philomena.Images.Image alias Philomena.Images.Image
alias Philomena.Images alias Philomena.Images
@ -34,7 +34,8 @@ defmodule PhilomenaWeb.Image.DescriptionController do
Images.reindex_image(image) Images.reindex_image(image)
body = TextileRenderer.render_one(%{body: image.description}, conn) body =
TextRenderer.render_one(%{body: image.description, body_md: image.description_md}, conn)
conn conn
|> put_view(PhilomenaWeb.ImageView) |> put_view(PhilomenaWeb.ImageView)

View file

@ -4,7 +4,7 @@ defmodule PhilomenaWeb.ImageController do
alias PhilomenaWeb.ImageLoader alias PhilomenaWeb.ImageLoader
alias PhilomenaWeb.CommentLoader alias PhilomenaWeb.CommentLoader
alias PhilomenaWeb.NotificationCountPlug alias PhilomenaWeb.NotificationCountPlug
alias PhilomenaWeb.TextileRenderer alias PhilomenaWeb.TextRenderer
alias Philomena.{ alias Philomena.{
Images, Images,
@ -63,13 +63,13 @@ defmodule PhilomenaWeb.ImageController do
comments = CommentLoader.load_comments(conn, image) comments = CommentLoader.load_comments(conn, image)
rendered = TextileRenderer.render_collection(comments.entries, conn) rendered = TextRenderer.render_collection(comments.entries, conn)
comments = %{comments | entries: Enum.zip(comments.entries, rendered)} comments = %{comments | entries: Enum.zip(comments.entries, rendered)}
description = description =
%{body: image.description} %{body: image.description, body_md: image.description_md}
|> TextileRenderer.render_one(conn) |> TextRenderer.render_one(conn)
interactions = Interactions.user_interactions([image], conn.assigns.current_user) interactions = Interactions.user_interactions([image], conn.assigns.current_user)

View file

@ -1,7 +1,7 @@
defmodule PhilomenaWeb.Post.PreviewController do defmodule PhilomenaWeb.Post.PreviewController do
use PhilomenaWeb, :controller use PhilomenaWeb, :controller
alias PhilomenaWeb.TextileRenderer alias PhilomenaWeb.TextRenderer
alias Philomena.Posts.Post alias Philomena.Posts.Post
alias Philomena.Repo alias Philomena.Repo
@ -11,7 +11,7 @@ defmodule PhilomenaWeb.Post.PreviewController do
anonymous = params["anonymous"] == true anonymous = params["anonymous"] == true
post = %Post{user: user, body: body, anonymous: anonymous} post = %Post{user: user, body: body, anonymous: anonymous}
rendered = TextileRenderer.render_one(post, conn) rendered = TextRenderer.render_one(post, conn)
render(conn, "create.html", layout: false, post: post, body: rendered) render(conn, "create.html", layout: false, post: post, body: rendered)
end end

View file

@ -1,7 +1,7 @@
defmodule PhilomenaWeb.PostController do defmodule PhilomenaWeb.PostController do
use PhilomenaWeb, :controller use PhilomenaWeb, :controller
alias PhilomenaWeb.TextileRenderer alias PhilomenaWeb.TextRenderer
alias Philomena.Elasticsearch alias Philomena.Elasticsearch
alias Philomena.{Posts.Query, Posts.Post} alias Philomena.{Posts.Query, Posts.Post}
import Ecto.Query import Ecto.Query
@ -36,7 +36,7 @@ defmodule PhilomenaWeb.PostController do
preload(Post, [:deleted_by, topic: :forum, user: [awards: :badge]]) preload(Post, [:deleted_by, topic: :forum, user: [awards: :badge]])
) )
rendered = TextileRenderer.render_collection(posts.entries, conn) rendered = TextRenderer.render_collection(posts.entries, conn)
posts = %{posts | entries: Enum.zip(rendered, posts.entries)} posts = %{posts | entries: Enum.zip(rendered, posts.entries)}

View file

@ -3,7 +3,7 @@ defmodule PhilomenaWeb.Profile.CommissionController do
alias Philomena.Commissions.Commission alias Philomena.Commissions.Commission
alias Philomena.Commissions alias Philomena.Commissions
alias PhilomenaWeb.TextileRenderer alias PhilomenaWeb.TextRenderer
alias Philomena.Users.User alias Philomena.Users.User
plug PhilomenaWeb.FilterBannedUsersPlug when action in [:new, :create, :edit, :update, :delete] plug PhilomenaWeb.FilterBannedUsersPlug when action in [:new, :create, :edit, :update, :delete]
@ -36,21 +36,21 @@ defmodule PhilomenaWeb.Profile.CommissionController do
item_descriptions = item_descriptions =
items items
|> Enum.map(&%{body: &1.description}) |> Enum.map(&%{body: &1.description, body_md: &1.description_md})
|> TextileRenderer.render_collection(conn) |> TextRenderer.render_collection(conn)
item_add_ons = item_add_ons =
items items
|> Enum.map(&%{body: &1.add_ons}) |> Enum.map(&%{body: &1.add_ons, body_md: &1.add_ons_md})
|> TextileRenderer.render_collection(conn) |> TextRenderer.render_collection(conn)
[information, contact, will_create, will_not_create] = [information, contact, will_create, will_not_create] =
TextileRenderer.render_collection( TextRenderer.render_collection(
[ [
%{body: commission.information || ""}, %{body_md: commission.information_md, body: commission.information || ""},
%{body: commission.contact || ""}, %{body_md: commission.contact_md, body: commission.contact || ""},
%{body: commission.will_create || ""}, %{body_md: commission.will_create_md, body: commission.will_create || ""},
%{body: commission.will_not_create || ""} %{body_md: commission.will_not_create_md, body: commission.will_not_create || ""}
], ],
conn conn
) )

View file

@ -3,7 +3,7 @@ defmodule PhilomenaWeb.Profile.DetailController do
alias Philomena.UserNameChanges.UserNameChange alias Philomena.UserNameChanges.UserNameChange
alias Philomena.ModNotes.ModNote alias Philomena.ModNotes.ModNote
alias PhilomenaWeb.TextileRenderer alias PhilomenaWeb.TextRenderer
alias Philomena.Polymorphic alias Philomena.Polymorphic
alias Philomena.Users.User alias Philomena.Users.User
alias Philomena.Repo alias Philomena.Repo
@ -30,7 +30,7 @@ defmodule PhilomenaWeb.Profile.DetailController do
mod_notes = mod_notes =
mod_notes mod_notes
|> TextileRenderer.render_collection(conn) |> TextRenderer.render_collection(conn)
|> Enum.zip(mod_notes) |> Enum.zip(mod_notes)
name_changes = name_changes =

View file

@ -3,7 +3,7 @@ defmodule PhilomenaWeb.ProfileController do
alias PhilomenaWeb.ImageLoader alias PhilomenaWeb.ImageLoader
alias Philomena.Elasticsearch alias Philomena.Elasticsearch
alias PhilomenaWeb.TextileRenderer alias PhilomenaWeb.TextRenderer
alias Philomena.UserStatistics.UserStatistic alias Philomena.UserStatistics.UserStatistic
alias Philomena.Users.User alias Philomena.Users.User
alias Philomena.Bans alias Philomena.Bans
@ -131,12 +131,14 @@ defmodule PhilomenaWeb.ProfileController do
recent_comments = recent_comments =
recent_comments recent_comments
|> Enum.filter(&Canada.Can.can?(current_user, :show, &1.image)) |> Enum.filter(&Canada.Can.can?(current_user, :show, &1.image))
|> TextileRenderer.render_collection(conn) |> TextRenderer.render_collection(conn)
|> Enum.zip(recent_comments) |> Enum.zip(recent_comments)
about_me = TextileRenderer.render_one(%{body: user.description || ""}, conn) about_me =
TextRenderer.render_one(%{body_md: user.description_md, body: user.description || ""}, conn)
scratchpad = TextileRenderer.render_one(%{body: user.scratchpad || ""}, conn) scratchpad =
TextRenderer.render_one(%{body_md: user.scratchpad_md, body: user.scratchpad || ""}, conn)
commission_information = commission_info(user.commission, conn) commission_information = commission_info(user.commission, conn)
@ -214,8 +216,9 @@ defmodule PhilomenaWeb.ProfileController do
defp map_fetch(nil, _field_name), do: nil defp map_fetch(nil, _field_name), do: nil
defp map_fetch(map, field_name), do: Map.get(map, field_name) defp map_fetch(map, field_name), do: Map.get(map, field_name)
defp commission_info(%{information: info}, conn) when info not in [nil, ""], defp commission_info(%{information: info, information_md: info_md}, conn)
do: TextileRenderer.render_one(%{body: info}, conn) when info not in [nil, ""],
do: TextRenderer.render_one(%{body: info, body_md: info_md}, conn)
defp commission_info(_commission, _conn), do: "" defp commission_info(_commission, _conn), do: ""
@ -282,7 +285,7 @@ defmodule PhilomenaWeb.ProfileController do
mod_notes = mod_notes =
mod_notes mod_notes
|> TextileRenderer.render_collection(conn) |> TextRenderer.render_collection(conn)
|> Enum.zip(mod_notes) |> Enum.zip(mod_notes)
assign(conn, :mod_notes, mod_notes) assign(conn, :mod_notes, mod_notes)

View file

@ -5,7 +5,7 @@ defmodule PhilomenaWeb.TagController do
alias Philomena.Elasticsearch alias Philomena.Elasticsearch
alias Philomena.{Tags, Tags.Tag} alias Philomena.{Tags, Tags.Tag}
alias Philomena.{Images, Images.Image} alias Philomena.{Images, Images.Image}
alias PhilomenaWeb.TextileRenderer alias PhilomenaWeb.TextRenderer
alias Philomena.Interactions alias Philomena.Interactions
import Ecto.Query import Ecto.Query
@ -61,11 +61,12 @@ defmodule PhilomenaWeb.TagController do
interactions = Interactions.user_interactions(images, user) interactions = Interactions.user_interactions(images, user)
body = TextileRenderer.render_one(%{body: tag.description || ""}, conn) body =
TextRenderer.render_one(%{body_md: tag.description_md, body: tag.description || ""}, conn)
dnp_bodies = dnp_bodies =
TextileRenderer.render_collection( TextRenderer.render_collection(
Enum.map(tag.dnp_entries, &%{body: &1.conditions || ""}), Enum.map(tag.dnp_entries, &%{body_md: &1.conditions_md, body: &1.conditions || ""}),
conn conn
) )

View file

@ -5,7 +5,7 @@ defmodule PhilomenaWeb.TopicController do
alias Philomena.{Forums.Forum, Topics.Topic, Posts.Post, Polls.Poll, PollOptions.PollOption} alias Philomena.{Forums.Forum, Topics.Topic, Posts.Post, Polls.Poll, PollOptions.PollOption}
alias Philomena.{Forums, Topics, Polls, Posts} alias Philomena.{Forums, Topics, Polls, Posts}
alias Philomena.PollVotes alias Philomena.PollVotes
alias PhilomenaWeb.TextileRenderer alias PhilomenaWeb.TextRenderer
alias Philomena.Repo alias Philomena.Repo
import Ecto.Query import Ecto.Query
@ -60,7 +60,7 @@ defmodule PhilomenaWeb.TopicController do
|> preload([:deleted_by, :topic, topic: :forum, user: [awards: :badge]]) |> preload([:deleted_by, :topic, topic: :forum, user: [awards: :badge]])
|> Repo.all() |> Repo.all()
rendered = TextileRenderer.render_collection(posts, conn) rendered = TextRenderer.render_collection(posts, conn)
posts = Enum.zip(posts, rendered) posts = Enum.zip(posts, rendered)

View file

@ -2,7 +2,7 @@ defmodule PhilomenaWeb.ImageLoader do
alias PhilomenaWeb.ImageSorter alias PhilomenaWeb.ImageSorter
alias Philomena.Elasticsearch alias Philomena.Elasticsearch
alias Philomena.Images.{Image, Query} alias Philomena.Images.{Image, Query}
alias PhilomenaWeb.TextileRenderer alias PhilomenaWeb.TextRenderer
alias Philomena.Tags.Tag alias Philomena.Tags.Tag
alias Philomena.Repo alias Philomena.Repo
import Ecto.Query import Ecto.Query
@ -132,14 +132,15 @@ defmodule PhilomenaWeb.ImageLoader do
defp render_bodies([tag], conn) do defp render_bodies([tag], conn) do
dnp_bodies = dnp_bodies =
TextileRenderer.render_collection( TextRenderer.render_collection(
Enum.map(tag.dnp_entries, &%{body: &1.conditions || ""}), Enum.map(tag.dnp_entries, &%{body_md: &1.conditions_md, body: &1.conditions || ""}),
conn conn
) )
dnp_entries = Enum.zip(dnp_bodies, tag.dnp_entries) dnp_entries = Enum.zip(dnp_bodies, tag.dnp_entries)
description = TextileRenderer.render_one(%{body: tag.description || ""}, conn) description =
TextRenderer.render_one(%{body_md: tag.description_md, body: tag.description || ""}, conn)
[{tag, description, dnp_entries}] [{tag, description, dnp_entries}]
end end

View file

@ -0,0 +1,106 @@
defmodule PhilomenaWeb.MarkdownRenderer do
alias Philomena.Markdown
alias Philomena.Images.Image
alias Philomena.Repo
import Phoenix.HTML
import Phoenix.HTML.Link
import Ecto.Query
@image_view Module.concat(["PhilomenaWeb.ImageView"])
def render(text, conn) do
images = find_images(text)
representations = render_representations(images, conn)
Markdown.to_html(text, representations)
end
defp find_images(text) do
Regex.scan(~r/>>(\d+)([tsp])?/, text, capture: :all_but_first)
|> Enum.map(fn matches ->
[Enum.at(matches, 0) |> String.to_integer(), Enum.at(matches, 1) || ""]
end)
|> Enum.filter(fn m -> Enum.at(m, 0) < 2_147_483_647 end)
end
defp load_images(images) do
ids = Enum.map(images, fn m -> Enum.at(m, 0) end)
Image
|> where([i], i.id in ^ids)
|> preload(tags: :aliases)
|> Repo.all()
|> Map.new(&{&1.id, &1})
end
defp link_suffix(image) do
cond do
not is_nil(image.duplicate_id) ->
" (merged)"
image.hidden_from_users ->
" (deleted)"
true ->
""
end
end
defp render_representations(images, conn) do
loaded_images = load_images(images)
images
|> Enum.map(fn group ->
img = loaded_images[Enum.at(group, 0)]
text = "#{Enum.at(group, 0)}#{Enum.at(group, 1)}"
rendered =
cond do
img != nil ->
case group do
[_id, "p"] when not img.hidden_from_users ->
Phoenix.View.render(@image_view, "_image_target.html",
image: img,
size: :medium,
conn: conn
)
|> safe_to_string()
[_id, "t"] when not img.hidden_from_users ->
Phoenix.View.render(@image_view, "_image_target.html",
image: img,
size: :small,
conn: conn
)
|> safe_to_string()
[_id, "s"] when not img.hidden_from_users ->
Phoenix.View.render(@image_view, "_image_target.html",
image: img,
size: :thumb_small,
conn: conn
)
|> safe_to_string()
[_id, ""] ->
link(">>#{img.id}#{link_suffix(img)}", to: "/images/#{img.id}")
|> safe_to_string()
[_id, suffix] when suffix in ["t", "s", "p"] ->
link(">>#{img.id}#{suffix}#{link_suffix(img)}", to: "/images/#{img.id}")
|> safe_to_string()
# This condition should never trigger, but let's leave it here just in case.
[id, suffix] ->
">>#{id}#{suffix}"
end
true ->
">>#{text}"
end
[text, rendered]
end)
|> Map.new(fn [id, html] -> {id, html} end)
end
end

View file

@ -0,0 +1,19 @@
defmodule PhilomenaWeb.TextRenderer do
alias PhilomenaWeb.MarkdownRenderer
alias PhilomenaWeb.TextileMarkdownRenderer
def render_one(item, conn) do
hd(render_collection([item], conn))
end
def render_collection(items, conn) do
Enum.map(items, fn item ->
if Map.has_key?(item, :body_md) && item.body_md != nil && item.body_md != "" do
MarkdownRenderer.render(item.body_md, conn)
else
markdown = TextileMarkdownRenderer.render_one(item)
MarkdownRenderer.render(markdown, conn)
end
end)
end
end

View file

@ -0,0 +1,22 @@
defmodule PhilomenaWeb.TextileMarkdownRenderer do
alias Philomena.Textile.ParserMarkdown
def render_one(post) do
hd(render_collection([post]))
end
def render_collection(posts) do
opts = %{image_transform: &Camo.Image.image_url/1}
parsed = Enum.map(posts, &ParserMarkdown.parse(opts, &1.body))
parsed
|> Enum.map(fn tree ->
tree
|> Enum.map(fn
{_k, text} ->
text
end)
|> Enum.join()
end)
end
end

View file

@ -9,42 +9,32 @@ defmodule PhilomenaWeb.TextileRenderer do
# Kill bogus compile time dependency on ImageView # Kill bogus compile time dependency on ImageView
@image_view Module.concat(["PhilomenaWeb.ImageView"]) @image_view Module.concat(["PhilomenaWeb.ImageView"])
def render_one(post, conn) do def render(text, conn) do
hd(render_collection([post], conn))
end
def render_collection(posts, conn) do
opts = %{image_transform: &Camo.Image.image_url/1} opts = %{image_transform: &Camo.Image.image_url/1}
parsed = Enum.map(posts, &Parser.parse(opts, &1.body)) parsed = Parser.parse(opts, text)
images = images =
parsed parsed
|> Enum.flat_map(fn tree -> |> Enum.flat_map(fn
tree {:text, text} ->
|> Enum.flat_map(fn [text]
{:text, text} ->
[text]
_ -> _ ->
[] []
end)
end) end)
|> find_images |> find_images
parsed parsed
|> Enum.map(fn tree -> |> Enum.map(fn
tree {:text, text} ->
|> Enum.map(fn text
{:text, text} -> |> replacement_entities()
text |> replacement_images(conn, images)
|> replacement_entities()
|> replacement_images(conn, images)
{_k, markup} -> {_k, markup} ->
markup markup
end)
|> Enum.join()
end) end)
|> Enum.join()
end end
defp replacement_entities(t) do defp replacement_entities(t) do
@ -99,11 +89,11 @@ defmodule PhilomenaWeb.TextileRenderer do
|> safe_to_string() |> safe_to_string()
[image, suffix] when suffix in ["p", "t", "s"] -> [image, suffix] when suffix in ["p", "t", "s"] ->
link(">>#{image.id}#{suffix}#{link_postfix(image)}", to: "/#{image.id}") link(">>#{image.id}#{suffix}#{link_postfix(image)}", to: "/images/#{image.id}")
|> safe_to_string() |> safe_to_string()
[image] -> [image] ->
link(">>#{image.id}#{link_postfix(image)}", to: "/#{image.id}") link(">>#{image.id}#{link_postfix(image)}", to: "/images/#{image.id}")
|> safe_to_string() |> safe_to_string()
end end
end) end)

View file

@ -1,17 +1,18 @@
defmodule PhilomenaWeb.ErrorView do defmodule PhilomenaWeb.ErrorView do
use PhilomenaWeb, :view use PhilomenaWeb, :view
import PhilomenaWeb.LayoutView, only: [ import PhilomenaWeb.LayoutView,
stylesheet_path: 2, only: [
dark_stylesheet_path: 1, stylesheet_path: 2,
viewport_meta_tag: 1 dark_stylesheet_path: 1,
] viewport_meta_tag: 1
]
@codes %{ @codes %{
400 => {"Bad Request", "Couldn't process your request!"}, 400 => {"Bad Request", "Couldn't process your request!"},
403 => {"Forbidden", "Not allowed to access this page (are your cookies enabled?)"}, 403 => {"Forbidden", "Not allowed to access this page (are your cookies enabled?)"},
404 => {"Not Found", "Couldn't find what you were looking for!"}, 404 => {"Not Found", "Couldn't find what you were looking for!"},
500 => {"Internal Error", "Couldn't process your request!"}, 500 => {"Internal Error", "Couldn't process your request!"}
} }
# By default, Phoenix returns the status message from # By default, Phoenix returns the status message from

View file

@ -11,7 +11,8 @@ defmodule Philomena.MixProject do
start_permanent: Mix.env() == :prod, start_permanent: Mix.env() == :prod,
aliases: aliases(), aliases: aliases(),
deps: deps(), deps: deps(),
dialyzer: [plt_add_apps: [:mix]] dialyzer: [plt_add_apps: [:mix]],
rustler_crates: [philomena_markdown: []]
] ]
end end
@ -69,6 +70,9 @@ defmodule Philomena.MixProject do
{:mint, "~> 1.2"}, {:mint, "~> 1.2"},
{:exq, "~> 0.14"}, {:exq, "~> 0.14"},
# Markdown
{:rustler, "~> 0.22"},
# Linting # Linting
{:credo, "~> 1.5", only: [:dev, :test], override: true}, {:credo, "~> 1.5", only: [:dev, :test], override: true},
{:credo_envvar, "~> 0.1", only: [:dev, :test], runtime: false}, {:credo_envvar, "~> 0.1", only: [:dev, :test], runtime: false},

View file

@ -12,6 +12,7 @@
"comeonin": {:hex, :comeonin, "5.3.2", "5c2f893d05c56ae3f5e24c1b983c2d5dfb88c6d979c9287a76a7feb1e1d8d646", [:mix], [], "hexpm", "d0993402844c49539aeadb3fe46a3c9bd190f1ecf86b6f9ebd71957534c95f04"}, "comeonin": {:hex, :comeonin, "5.3.2", "5c2f893d05c56ae3f5e24c1b983c2d5dfb88c6d979c9287a76a7feb1e1d8d646", [:mix], [], "hexpm", "d0993402844c49539aeadb3fe46a3c9bd190f1ecf86b6f9ebd71957534c95f04"},
"connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"}, "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
"cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"}, "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.1", "ebd1a1d7aff97f27c66654e78ece187abdc646992714164380d8a041eda16754", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a6efd3366130eab84ca372cbd4a7d3c3a97bdfcfb4911233b035d117063f0af"},
"cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"}, "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
"credo": {:hex, :credo, "1.5.6", "e04cc0fdc236fefbb578e0c04bd01a471081616e741d386909e527ac146016c6", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "4b52a3e558bd64e30de62a648518a5ea2b6e3e5d2b164ef5296244753fc7eb17"}, "credo": {:hex, :credo, "1.5.6", "e04cc0fdc236fefbb578e0c04bd01a471081616e741d386909e527ac146016c6", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "4b52a3e558bd64e30de62a648518a5ea2b6e3e5d2b164ef5296244753fc7eb17"},
"credo_envvar": {:hex, :credo_envvar, "0.1.4", "40817c10334e400f031012c0510bfa0d8725c19d867e4ae39cf14f2cbebc3b20", [:mix], [{:credo, "~> 1.0", [hex: :credo, repo: "hexpm", optional: false]}], "hexpm", "5055cdb4bcbaf7d423bc2bb3ac62b4e2d825e2b1e816884c468dee59d0363009"}, "credo_envvar": {:hex, :credo_envvar, "0.1.4", "40817c10334e400f031012c0510bfa0d8725c19d867e4ae39cf14f2cbebc3b20", [:mix], [{:credo, "~> 1.0", [hex: :credo, repo: "hexpm", optional: false]}], "hexpm", "5055cdb4bcbaf7d423bc2bb3ac62b4e2d825e2b1e816884c468dee59d0363009"},
@ -19,9 +20,9 @@
"db_connection": {:hex, :db_connection, "2.4.0", "d04b1b73795dae60cead94189f1b8a51cc9e1f911c234cc23074017c43c031e5", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ad416c21ad9f61b3103d254a71b63696ecadb6a917b36f563921e0de00d7d7c8"}, "db_connection": {:hex, :db_connection, "2.4.0", "d04b1b73795dae60cead94189f1b8a51cc9e1f911c234cc23074017c43c031e5", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ad416c21ad9f61b3103d254a71b63696ecadb6a917b36f563921e0de00d7d7c8"},
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"}, "decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
"dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"}, "dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"},
"ecto": {:hex, :ecto, "3.7.1", "a20598862351b29f80f285b21ec5297da1181c0442687f9b8329f0445d228892", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d36e5b39fc479e654cffd4dbe1865d9716e4a9b6311faff799b6f90ab81b8638"}, "ecto": {:hex, :ecto, "3.5.8", "8ebf12be6016cb99313348ba7bb4612f4114b9a506d6da79a2adc7ef449340bc", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ea0be182ea8922eb7742e3ae8e71b67ee00ae177de1bf76210299a5f16ba4c77"},
"ecto_network": {:hex, :ecto_network, "1.3.0", "1e77fa37c20e0f6a426d3862732f3317b0fa4c18f123d325f81752a491d7304e", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:phoenix_html, ">= 0.0.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.14.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm", "053a5e46ef2837e8ea5ea97c82fa0f5494699209eddd764e663c85f11b2865bd"}, "ecto_network": {:hex, :ecto_network, "1.3.0", "1e77fa37c20e0f6a426d3862732f3317b0fa4c18f123d325f81752a491d7304e", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:phoenix_html, ">= 0.0.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.14.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm", "053a5e46ef2837e8ea5ea97c82fa0f5494699209eddd764e663c85f11b2865bd"},
"ecto_sql": {:hex, :ecto_sql, "3.7.0", "2fcaad4ab0c8d76a5afbef078162806adbe709c04160aca58400d5cbbe8eeac6", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.4.0 or ~> 0.5.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a26135dfa1d99bf87a928c464cfa25bba6535a4fe761eefa56077a4febc60f70"}, "ecto_sql": {:hex, :ecto_sql, "3.5.0", "760aa2935cc80b72da83fbd8cc97923623a2401915c308afea2cf2b0aabf4b2e", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.5.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0 or ~> 0.4.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.0", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3bab456e3ebb5680b327313f57ebb5356882a59fe04964a03232a83dc4c44aa2"},
"elastix": {:hex, :elastix, "0.10.0", "7567da885677ba9deffc20063db5f3ca8cd10f23cff1ab3ed9c52b7063b7e340", [:mix], [{:httpoison, "~> 1.4", [hex: :httpoison, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0", [hex: :poison, repo: "hexpm", optional: true]}, {:retry, "~> 0.8", [hex: :retry, repo: "hexpm", optional: false]}], "hexpm", "5fb342ce068b20f7845f5dd198c2dc80d967deafaa940a6e51b846db82696d1d"}, "elastix": {:hex, :elastix, "0.10.0", "7567da885677ba9deffc20063db5f3ca8cd10f23cff1ab3ed9c52b7063b7e340", [:mix], [{:httpoison, "~> 1.4", [hex: :httpoison, repo: "hexpm", optional: false]}, {:poison, "~> 3.0 or ~> 4.0", [hex: :poison, repo: "hexpm", optional: true]}, {:retry, "~> 0.8", [hex: :retry, repo: "hexpm", optional: false]}], "hexpm", "5fb342ce068b20f7845f5dd198c2dc80d967deafaa940a6e51b846db82696d1d"},
"elixir_make": {:hex, :elixir_make, "0.6.2", "7dffacd77dec4c37b39af867cedaabb0b59f6a871f89722c25b28fcd4bd70530", [:mix], [], "hexpm", "03e49eadda22526a7e5279d53321d1cced6552f344ba4e03e619063de75348d9"}, "elixir_make": {:hex, :elixir_make, "0.6.2", "7dffacd77dec4c37b39af867cedaabb0b59f6a871f89722c25b28fcd4bd70530", [:mix], [], "hexpm", "03e49eadda22526a7e5279d53321d1cced6552f344ba4e03e619063de75348d9"},
"elixir_uuid": {:hex, :elixir_uuid, "1.2.1", "dce506597acb7e6b0daeaff52ff6a9043f5919a4c3315abb4143f0b00378c097", [:mix], [], "hexpm", "f7eba2ea6c3555cea09706492716b0d87397b88946e6380898c2889d68585752"}, "elixir_uuid": {:hex, :elixir_uuid, "1.2.1", "dce506597acb7e6b0daeaff52ff6a9043f5919a4c3315abb4143f0b00378c097", [:mix], [], "hexpm", "f7eba2ea6c3555cea09706492716b0d87397b88946e6380898c2889d68585752"},
@ -39,13 +40,13 @@
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"}, "mime": {:hex, :mime, "1.6.0", "dabde576a497cef4bbdd60aceee8160e02a6c89250d6c0b29e56c0dfb00db3d2", [:mix], [], "hexpm", "31a1a8613f8321143dde1dafc36006a17d28d02bdfecb9e95a880fa7aabd19a7"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"}, "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"mint": {:hex, :mint, "1.3.0", "396b3301102f7b775e103da5a20494b25753aed818d6d6f0ad222a3a018c3600", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "a9aac960562e43ca69a77e5176576abfa78b8398cec5543dd4fb4ab0131d5c1e"}, "mint": {:hex, :mint, "1.4.0", "cd7d2451b201fc8e4a8fd86257fb3878d9e3752899eb67b0c5b25b180bde1212", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "10a99e144b815cbf8522dccbc8199d15802440fc7a64d67b6853adb6fa170217"},
"mix_audit": {:hex, :mix_audit, "0.1.4", "35c424173a574436a80ad7f63cf014a7d9ce727de8cd4e7b4138d90b11aec043", [:make, :mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.4.0", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "7a43fee661bcadbad31aa04a86d33a890421c174723814b8a3a7f0e7076936a1"}, "mix_audit": {:hex, :mix_audit, "0.1.4", "35c424173a574436a80ad7f63cf014a7d9ce727de8cd4e7b4138d90b11aec043", [:make, :mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.4.0", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "7a43fee661bcadbad31aa04a86d33a890421c174723814b8a3a7f0e7076936a1"},
"neotoma": {:hex, :neotoma, "1.7.3", "d8bd5404b73273989946e4f4f6d529e5c2088f5fa1ca790b4dbe81f4be408e61", [:rebar], [], "hexpm", "2da322b9b1567ffa0706a7f30f6bbbde70835ae44a1050615f4b4a3d436e0f28"}, "neotoma": {:hex, :neotoma, "1.7.3", "d8bd5404b73273989946e4f4f6d529e5c2088f5fa1ca790b4dbe81f4be408e61", [:rebar], [], "hexpm", "2da322b9b1567ffa0706a7f30f6bbbde70835ae44a1050615f4b4a3d436e0f28"},
"nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"}, "nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"},
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"}, "parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
"pbkdf2": {:git, "https://github.com/code-time/erlang-pbkdf2.git", "f8f0012a97f58ade9c70ac93260e4259e4ca4b8d", [ref: "f8f0012a97f58ade9c70ac93260e4259e4ca4b8d"]}, "pbkdf2": {:git, "https://github.com/code-time/erlang-pbkdf2.git", "f8f0012a97f58ade9c70ac93260e4259e4ca4b8d", [ref: "f8f0012a97f58ade9c70ac93260e4259e4ca4b8d"]},
"phoenix": {:hex, :phoenix, "1.5.12", "75fddb14c720388eea93d33886166a690416a7ff8633fbd93f364355b6fe1166", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "8f0ae6734fcc18bbaa646c161e2febc46fb899eae43f82679b92530983324113"}, "phoenix": {:hex, :phoenix, "1.5.0", "59cf8c734a0e305736654961691aeaa11d80b96a0cc4aeb68d8610af42af1aef", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 2.13", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.1.2 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c695e372ea39914bb97d62ef632550bc3bb38a4bb78fa520f5d5d4be3630399e"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"},
"phoenix_html": {:hex, :phoenix_html, "2.14.3", "51f720d0d543e4e157ff06b65de38e13303d5778a7919bcc696599e5934271b8", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "efd697a7fff35a13eeeb6b43db884705cba353a1a41d127d118fda5f90c8e80f"}, "phoenix_html": {:hex, :phoenix_html, "2.14.3", "51f720d0d543e4e157ff06b65de38e13303d5778a7919bcc696599e5934271b8", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "efd697a7fff35a13eeeb6b43db884705cba353a1a41d127d118fda5f90c8e80f"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.3.3", "3a53772a6118d5679bf50fc1670505a290e32a1d195df9e069d8c53ab040c054", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "766796676e5f558dbae5d1bdb066849673e956005e3730dfd5affd7a6da4abac"}, "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.3.3", "3a53772a6118d5679bf50fc1670505a290e32a1d195df9e069d8c53ab040c054", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "766796676e5f558dbae5d1bdb066849673e956005e3730dfd5affd7a6da4abac"},
@ -53,25 +54,27 @@
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.0.0", "a1ae76717bb168cdeb10ec9d92d1480fec99e3080f011402c0a2d68d47395ffb", [:mix], [], "hexpm", "c52d948c4f261577b9c6fa804be91884b381a7f8f18450c5045975435350f771"},
"phoenix_pubsub_redis": {:hex, :phoenix_pubsub_redis, "3.0.1", "d4d856b1e57a21358e448543e1d091e07e83403dde4383b8be04ed9d2c201cbc", [:mix], [{:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5.1 or ~> 1.6", [hex: :poolboy, repo: "hexpm", optional: false]}, {:redix, "~> 0.10.0 or ~> 1.0", [hex: :redix, repo: "hexpm", optional: false]}], "hexpm", "0b36a17ff6e9a56159f8df8933d62b5c1f0695eae995a02e0c86c035ace6a309"}, "phoenix_pubsub_redis": {:hex, :phoenix_pubsub_redis, "3.0.1", "d4d856b1e57a21358e448543e1d091e07e83403dde4383b8be04ed9d2c201cbc", [:mix], [{:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5.1 or ~> 1.6", [hex: :poolboy, repo: "hexpm", optional: false]}, {:redix, "~> 0.10.0 or ~> 1.0", [hex: :redix, repo: "hexpm", optional: false]}], "hexpm", "0b36a17ff6e9a56159f8df8933d62b5c1f0695eae995a02e0c86c035ace6a309"},
"phoenix_slime": {:hex, :phoenix_slime, "0.13.1", "a5d4d8febb87a618b02d690519f7106832c8bd0b4d1937fbba73d6e8666f2891", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.13", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:slime, "~> 1.0", [hex: :slime, repo: "hexpm", optional: false]}], "hexpm", "ff818744be2c903fb0174ba22b230c1c335238578fccf274b1d95d08f4844377"}, "phoenix_slime": {:hex, :phoenix_slime, "0.13.1", "a5d4d8febb87a618b02d690519f7106832c8bd0b4d1937fbba73d6e8666f2891", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.13", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:slime, "~> 1.0", [hex: :slime, repo: "hexpm", optional: false]}], "hexpm", "ff818744be2c903fb0174ba22b230c1c335238578fccf274b1d95d08f4844377"},
"plug": {:hex, :plug, "1.12.1", "645678c800601d8d9f27ad1aebba1fdb9ce5b2623ddb961a074da0b96c35187d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d57e799a777bc20494b784966dc5fbda91eb4a09f571f76545b72a634ce0d30b"}, "plug": {:hex, :plug, "1.10.0", "6508295cbeb4c654860845fb95260737e4a8838d34d115ad76cd487584e2fc4d", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "422a9727e667be1bf5ab1de03be6fa0ad67b775b2d84ed908f3264415ef29d4a"},
"plug_cowboy": {:hex, :plug_cowboy, "2.3.0", "149a50e05cb73c12aad6506a371cd75750c0b19a32f81866e1a323dda9e0e99d", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bc595a1870cef13f9c1e03df56d96804db7f702175e4ccacdb8fc75c02a7b97e"}, "plug_cowboy": {:hex, :plug_cowboy, "2.5.2", "62894ccd601cf9597e2c23911ff12798a8a18d237e9739f58a6b04e4988899fe", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ea6e87f774c8608d60c8d34022a7d073bd7680a0a013f049fc62bf35efea1044"},
"plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"}, "plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"},
"poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"}, "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
"postgrex": {:hex, :postgrex, "0.15.10", "2809dee1b1d76f7cbabe570b2a9285c2e7b41be60cf792f5f2804a54b838a067", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "1560ca427542f6b213f8e281633ae1a3b31cdbcd84ebd7f50628765b8f6132be"}, "postgrex": {:hex, :postgrex, "0.15.10", "2809dee1b1d76f7cbabe570b2a9285c2e7b41be60cf792f5f2804a54b838a067", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "1560ca427542f6b213f8e281633ae1a3b31cdbcd84ebd7f50628765b8f6132be"},
"pot": {:hex, :pot, "1.0.2", "13abb849139fdc04ab8154986abbcb63bdee5de6ed2ba7e1713527e33df923dd", [:rebar3], [], "hexpm", "78fe127f5a4f5f919d6ea5a2a671827bd53eb9d37e5b4128c0ad3df99856c2e0"}, "pot": {:hex, :pot, "1.0.2", "13abb849139fdc04ab8154986abbcb63bdee5de6ed2ba7e1713527e33df923dd", [:rebar3], [], "hexpm", "78fe127f5a4f5f919d6ea5a2a671827bd53eb9d37e5b4128c0ad3df99856c2e0"},
"qrcode": {:hex, :qrcode, "0.1.5", "551271830515c150f34568345b060c625deb0e6691db2a01b0a6de3aafc93886", [:mix], [], "hexpm", "a266b7fb7be0d3b713912055dde3575927eca920e5d604ded45cd534f6b7a447"}, "qrcode": {:hex, :qrcode, "0.1.5", "551271830515c150f34568345b060c625deb0e6691db2a01b0a6de3aafc93886", [:mix], [], "hexpm", "a266b7fb7be0d3b713912055dde3575927eca920e5d604ded45cd534f6b7a447"},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"redix": {:hex, :redix, "0.10.7", "758916c71fc09e223e18d6715344581d7768c430983dabf77e792ba2087729e6", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "73fdf73c0472278dc040dcd1a5da91d4febe218201ae8ac0454b37e136886c34"}, "redix": {:hex, :redix, "0.10.0", "886cfbb14f9b78b82f38963695be2c6ed54b4f5cf911acbf70278ba09144f55d", [:mix], [{:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d8266f5a13291f1d8d7003ad48820e80d34c48348dd762e6564a806cb4b5bc0f"},
"remote_ip": {:hex, :remote_ip, "0.2.1", "cd27cd8ea54ecaaf3532776ff4c5e353b3804e710302e88c01eadeaaf42e7e24", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:inet_cidr, "~> 1.0", [hex: :inet_cidr, repo: "hexpm", optional: false]}, {:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "2e7ab1a461cc3cd5719f37e116a08f45c8b8493923063631b164315d6b7ee8e0"}, "remote_ip": {:hex, :remote_ip, "0.2.1", "cd27cd8ea54ecaaf3532776ff4c5e353b3804e710302e88c01eadeaaf42e7e24", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:inet_cidr, "~> 1.0", [hex: :inet_cidr, repo: "hexpm", optional: false]}, {:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "2e7ab1a461cc3cd5719f37e116a08f45c8b8493923063631b164315d6b7ee8e0"},
"retry": {:hex, :retry, "0.14.1", "722d1b0cf87096b71213f5801d99fface7ca76adc83fc9dbf3e1daee952aef10", [:mix], [], "hexpm", "b3a609f286f6fe4f6b2c15f32cd4a8a60427d78d05d7b68c2dd9110981111ae0"}, "retry": {:hex, :retry, "0.14.1", "722d1b0cf87096b71213f5801d99fface7ca76adc83fc9dbf3e1daee952aef10", [:mix], [], "hexpm", "b3a609f286f6fe4f6b2c15f32cd4a8a60427d78d05d7b68c2dd9110981111ae0"},
"rustler": {:hex, :rustler, "0.22.0", "e2930f9d6933e910f87526bb0a7f904e32b62a7e838a3ca4a884ee7fdfb957ed", [:mix], [{:toml, "~> 0.5.2", [hex: :toml, repo: "hexpm", optional: false]}], "hexpm", "01f5989dd511ebec09be481e07d3c59773d5373c5061e09d3ebc3ef61811b49d"},
"scrivener": {:hex, :scrivener, "2.7.2", "1d913c965ec352650a7f864ad7fd8d80462f76a32f33d57d1e48bc5e9d40aba2", [:mix], [], "hexpm", "7866a0ec4d40274efbee1db8bead13a995ea4926ecd8203345af8f90d2b620d9"}, "scrivener": {:hex, :scrivener, "2.7.2", "1d913c965ec352650a7f864ad7fd8d80462f76a32f33d57d1e48bc5e9d40aba2", [:mix], [], "hexpm", "7866a0ec4d40274efbee1db8bead13a995ea4926ecd8203345af8f90d2b620d9"},
"scrivener_ecto": {:hex, :scrivener_ecto, "2.7.0", "cf64b8cb8a96cd131cdbcecf64e7fd395e21aaa1cb0236c42a7c2e34b0dca580", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:scrivener, "~> 2.4", [hex: :scrivener, repo: "hexpm", optional: false]}], "hexpm", "e809f171687806b0031129034352f5ae44849720c48dd839200adeaf0ac3e260"}, "scrivener_ecto": {:hex, :scrivener_ecto, "2.7.0", "cf64b8cb8a96cd131cdbcecf64e7fd395e21aaa1cb0236c42a7c2e34b0dca580", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:scrivener, "~> 2.4", [hex: :scrivener, repo: "hexpm", optional: false]}], "hexpm", "e809f171687806b0031129034352f5ae44849720c48dd839200adeaf0ac3e260"},
"secure_compare": {:hex, :secure_compare, "0.1.0", "01b3c93c8edb696e8a5b38397ed48e10958c8a5ec740606656445bcbec0aadb8", [:mix], [], "hexpm", "6391a49eb4a6182f0d7425842fc774bbed715e78b2bfb0c83b99c94e02c78b5c"}, "secure_compare": {:hex, :secure_compare, "0.1.0", "01b3c93c8edb696e8a5b38397ed48e10958c8a5ec740606656445bcbec0aadb8", [:mix], [], "hexpm", "6391a49eb4a6182f0d7425842fc774bbed715e78b2bfb0c83b99c94e02c78b5c"},
"slime": {:hex, :slime, "1.2.1", "71e036056051f0a6fae136af34eaa1322e8e11cdd2da3a56196fd31bca34dd49", [:mix], [{:neotoma, "~> 1.7", [hex: :neotoma, repo: "hexpm", optional: false]}], "hexpm", "298568e64291fed4eb690be094f6c46400daa03b594bab34fcaa0167e139c263"}, "slime": {:hex, :slime, "1.2.1", "71e036056051f0a6fae136af34eaa1322e8e11cdd2da3a56196fd31bca34dd49", [:mix], [{:neotoma, "~> 1.7", [hex: :neotoma, repo: "hexpm", optional: false]}], "hexpm", "298568e64291fed4eb690be094f6c46400daa03b594bab34fcaa0167e139c263"},
"sobelow": {:hex, :sobelow, "0.11.1", "23438964486f8112b41e743bbfd402da3e5b296fdc9eacab29914b79c48916dd", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "9897363a7eff96f4809304a90aad819e2ad5e5d24db547af502885146746a53c"}, "sobelow": {:hex, :sobelow, "0.11.1", "23438964486f8112b41e743bbfd402da3e5b296fdc9eacab29914b79c48916dd", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "9897363a7eff96f4809304a90aad819e2ad5e5d24db547af502885146746a53c"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
"telemetry": {:hex, :telemetry, "0.4.3", "a06428a514bdbc63293cd9a6263aad00ddeb66f608163bdec7c8995784080818", [:rebar3], [], "hexpm", "eb72b8365ffda5bed68a620d1da88525e326cb82a75ee61354fc24b844768041"}, "telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm", "e9e3cacfd37c1531c0ca70ca7c0c30ce2dbb02998a4f7719de180fe63f8d41e4"},
"tesla": {:hex, :tesla, "1.4.3", "f5a494e08fb1abe4fd9c28abb17f3d9b62b8f6fc492860baa91efb1aab61c8a0", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.3", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "e0755bb664bf4d664af72931f320c97adbf89da4586670f4864bf259b5750386"}, "tesla": {:hex, :tesla, "1.4.0", "1081bef0124b8bdec1c3d330bbe91956648fb008cf0d3950a369cda466a31a87", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.3", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "bf1374a5569f5fca8e641363b63f7347d680d91388880979a33bc12a6eb3e0aa"},
"toml": {:hex, :toml, "0.5.2", "e471388a8726d1ce51a6b32f864b8228a1eb8edc907a0edf2bb50eab9321b526", [:mix], [], "hexpm", "f1e3dabef71fb510d015fad18c0e05e7c57281001141504c6b69d94e99750a07"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
"yamerl": {:hex, :yamerl, "0.8.1", "07da13ffa1d8e13948943789665c62ccd679dfa7b324a4a2ed3149df17f453a4", [:rebar3], [], "hexpm", "96cb30f9d64344fed0ef8a92e9f16f207de6c04dfff4f366752ca79f5bceb23f"}, "yamerl": {:hex, :yamerl, "0.8.1", "07da13ffa1d8e13948943789665c62ccd679dfa7b324a4a2ed3149df17f453a4", [:rebar3], [], "hexpm", "96cb30f9d64344fed0ef8a92e9f16f207de6c04dfff4f366752ca79f5bceb23f"},
"yaml_elixir": {:hex, :yaml_elixir, "2.4.0", "2f444abc3c994c902851fde56b6a9cb82895c291c05a0490a289035c2e62ae71", [:mix], [{:yamerl, "~> 0.7", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "4e25a6d5c873e393689c6f1062c5ec90f6cd1be2527b073178ae37eae4c78bee"}, "yaml_elixir": {:hex, :yaml_elixir, "2.4.0", "2f444abc3c994c902851fde56b6a9cb82895c291c05a0490a289035c2e62ae71", [:mix], [{:yamerl, "~> 0.7", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "4e25a6d5c873e393689c6f1062c5ec90f6cd1be2527b073178ae37eae4c78bee"},

959
native/philomena/Cargo.lock generated Normal file
View file

@ -0,0 +1,959 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
dependencies = [
"winapi",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "base64"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "bincode"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
dependencies = [
"serde",
]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "block-buffer"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
dependencies = [
"block-padding",
"byte-tools",
"byteorder",
"generic-array",
]
[[package]]
name = "block-padding"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
dependencies = [
"byte-tools",
]
[[package]]
name = "bumpalo"
version = "3.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538"
[[package]]
name = "byte-tools"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
name = "clap"
version = "2.33.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim",
"textwrap",
"unicode-width",
"vec_map",
]
[[package]]
name = "comrak"
version = "0.12.1"
source = "git+https://github.com/philomena-dev/comrak?branch=main#3e2120b6b5d5d995b787dad27699f5bda4bc6112"
dependencies = [
"clap",
"entities",
"lazy_static",
"pest",
"pest_derive",
"regex",
"shell-words",
"syntect",
"twoway",
"typed-arena",
"unicode_categories",
"xdg",
]
[[package]]
name = "crc32fast"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
dependencies = [
"cfg-if",
]
[[package]]
name = "digest"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
dependencies = [
"generic-array",
]
[[package]]
name = "entities"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca"
[[package]]
name = "fake-simd"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]]
name = "flate2"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f"
dependencies = [
"cfg-if",
"crc32fast",
"libc",
"miniz_oxide",
]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "form_urlencoded"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
dependencies = [
"matches",
"percent-encoding",
]
[[package]]
name = "fs_extra"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394"
[[package]]
name = "generic-array"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
dependencies = [
"typenum",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "heck"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "idna"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "indexmap"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "itoa"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "jemalloc-sys"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d3b9f3f5c9b31aa0f5ed3260385ac205db665baa41d49bb8338008ae94ede45"
dependencies = [
"cc",
"fs_extra",
"libc",
]
[[package]]
name = "jemallocator"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43ae63fcfc45e99ab3d1b29a46782ad679e98436c3169d15a167a1108a724b69"
dependencies = [
"jemalloc-sys",
"libc",
]
[[package]]
name = "js-sys"
version = "0.3.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
version = "0.2.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103"
[[package]]
name = "line-wrap"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9"
dependencies = [
"safemem",
]
[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
]
[[package]]
name = "maplit"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]]
name = "matches"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "miniz_oxide"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
dependencies = [
"adler",
"autocfg",
]
[[package]]
name = "num-integer"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]]
name = "onig"
version = "6.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b16fd3c0e73b516af509c13c4ba76ec0c987ce20d78b38cff356b8d01fc6a6c0"
dependencies = [
"bitflags",
"lazy_static",
"libc",
"onig_sys",
]
[[package]]
name = "onig_sys"
version = "69.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fd9442a09e4fbd08d196ddf419b2c79a43c3a46c800320cc841d45c2449a240"
dependencies = [
"cc",
"pkg-config",
]
[[package]]
name = "opaque-debug"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pest"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
dependencies = [
"ucd-trie",
]
[[package]]
name = "pest_derive"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0"
dependencies = [
"pest",
"pest_generator",
]
[[package]]
name = "pest_generator"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "pest_meta"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d"
dependencies = [
"maplit",
"pest",
"sha-1",
]
[[package]]
name = "philomena"
version = "0.3.0"
dependencies = [
"base64",
"comrak",
"jemallocator",
"ring",
"rustler",
"url",
]
[[package]]
name = "pkg-config"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
[[package]]
name = "plist"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a38d026d73eeaf2ade76309d0c65db5a35ecf649e3cec428db316243ea9d6711"
dependencies = [
"base64",
"chrono",
"indexmap",
"line-wrap",
"serde",
"xml-rs",
]
[[package]]
name = "proc-macro2"
version = "1.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "ring"
version = "0.16.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
dependencies = [
"cc",
"libc",
"once_cell",
"spin",
"untrusted",
"web-sys",
"winapi",
]
[[package]]
name = "rustler"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b787d3b2a80007f41cd4c0c310cdeb3936192768159585f65ecc7e96faf97fc3"
dependencies = [
"lazy_static",
"rustler_codegen",
"rustler_sys",
]
[[package]]
name = "rustler_codegen"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5a1f867002b6f0130f47abf215cac4405646db6f5d7b009b21c890980490aa4"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "rustler_sys"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cb382fde4f421c51555919e9920b058c0286f6bf59e53d02eb4d281eae6758b"
dependencies = [
"unreachable",
]
[[package]]
name = "ryu"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "safemem"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "serde"
version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
[[package]]
name = "serde_derive"
version = "1.0.130"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "sha-1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
dependencies = [
"block-buffer",
"digest",
"fake-simd",
"opaque-debug",
]
[[package]]
name = "shell-words"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6fa3938c99da4914afedd13bf3d79bcb6c277d1b2c398d23257a304d9e1b074"
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "syn"
version = "1.0.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "syntect"
version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b20815bbe80ee0be06e6957450a841185fcf690fe0178f14d77a05ce2caa031"
dependencies = [
"bincode",
"bitflags",
"flate2",
"fnv",
"lazy_static",
"lazycell",
"onig",
"plist",
"regex-syntax",
"serde",
"serde_derive",
"serde_json",
"walkdir",
]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]]
name = "tinyvec"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5241dd6f21443a3606b432718b166d3cedc962fd4b8bea54a8bc7f514ebda986"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "twoway"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c57ffb460d7c24cd6eda43694110189030a3d1dfe418416d9468fd1c1d290b47"
dependencies = [
"memchr",
"unchecked-index",
]
[[package]]
name = "typed-arena"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9b2228007eba4120145f785df0f6c92ea538f5a3635a612ecf4e334c8c1446d"
[[package]]
name = "typenum"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec"
[[package]]
name = "ucd-trie"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
[[package]]
name = "unchecked-index"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eeba86d422ce181a719445e51872fa30f1f7413b62becb52e95ec91aa262d85c"
[[package]]
name = "unicode-bidi"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085"
[[package]]
name = "unicode-normalization"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-segmentation"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
[[package]]
name = "unicode-width"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "unicode_categories"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
[[package]]
name = "unreachable"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
dependencies = [
"void",
]
[[package]]
name = "untrusted"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "url"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
dependencies = [
"form_urlencoded",
"idna",
"matches",
"percent-encoding",
]
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "walkdir"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
dependencies = [
"same-file",
"winapi",
"winapi-util",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b"
dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
[[package]]
name = "web-sys"
version = "0.3.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "xdg"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"
[[package]]
name = "xml-rs"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"

View file

@ -0,0 +1,22 @@
[package]
name = "philomena"
version = "0.3.0"
authors = ["Xe <https://github.com/Xe>", "Luna <https://github.com/Meow>", "Liam White <https://github.com/liamwhite>"]
edition = "2018"
[lib]
name = "philomena"
path = "src/lib.rs"
crate-type = ["dylib"]
[dependencies]
comrak = { git = "https://github.com/philomena-dev/comrak", branch = "main" }
rustler = "0.22"
jemallocator = "0.3.2"
ring = "0.16"
base64 = "0.13"
url = "2.2"
[profile.release]
opt-level = 3
lto = true

View file

@ -0,0 +1,22 @@
# NIF for Elixir.Philomena.Markdown
## To build the NIF module:
- Make sure your projects `mix.exs` has the `:rustler` compiler listed in the `project` function: `compilers: [:rustler] ++ Mix.compilers()` If there already is a `:compilers` list, you should append `:rustler` to it.
- Add your crate to the `rustler_crates` attribute in the `project function. [See here](https://hexdocs.pm/rustler/basics.html#crate-configuration).
- Your NIF will now build along with your project.
## To load the NIF:
```elixir
defmodule Philomena.Markdown do
use Rustler, otp_app: <otp-app>, crate: "philomena_markdown"
# When your NIF is loaded, it will override this function.
def add(_a, _b), do: :erlang.nif_error(:nif_not_loaded)
end
```
## Examples
[This](https://github.com/hansihe/NifIo) is a complete example of a NIF written in Rust.

View file

@ -0,0 +1,44 @@
use ring::hmac;
use std::env;
use url::Url;
fn trusted_host(mut url: Url) -> Option<String> {
url.set_port(Some(443)).ok()?;
url.set_scheme("https").ok()?;
Some(url.to_string())
}
fn untrusted_host(url: Url, camo_host: String, camo_key: String) -> Option<String> {
let camo_url = format!("https://{}", camo_host);
let key = hmac::Key::new(hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY, camo_key.as_ref());
let tag = hmac::sign(&key, url.to_string().as_bytes());
let encoded = base64::encode_config(tag.as_ref(), base64::URL_SAFE_NO_PAD);
let encoded_url = base64::encode_config(url.as_ref(), base64::URL_SAFE_NO_PAD);
let path = format!("{}/{}", encoded, encoded_url);
let mut camo_uri = Url::parse(&camo_url).ok()?;
camo_uri.set_path(&path);
camo_uri.set_port(Some(443)).ok()?;
camo_uri.set_scheme("https").ok()?;
Some(camo_uri.to_string())
}
pub fn image_url(uri: String) -> Option<String> {
let cdn_host = env::var("CDN_HOST").ok()?;
let camo_host = env::var("CAMO_HOST").ok()?;
let camo_key = env::var("CAMO_KEY").ok()?;
if camo_key.is_empty() {
return Some(uri);
}
let url = Url::parse(&uri).ok()?;
match url.host_str() {
Some(hostname) if hostname == cdn_host || hostname == camo_host => trusted_host(url),
Some(_) => untrusted_host(url, camo_host, camo_key),
None => Some(String::from("")),
}
}

View file

@ -0,0 +1,32 @@
use jemallocator::Jemalloc;
use rustler::Term;
mod camo;
mod markdown;
#[global_allocator]
static GLOBAL: Jemalloc = Jemalloc;
rustler::init! {
"Elixir.Philomena.Native",
[markdown_to_html, markdown_to_html_unsafe, camo_image_url]
}
// Markdown NIF wrappers.
#[rustler::nif(schedule = "DirtyCpu")]
fn markdown_to_html<'a>(input: String, reps: Term<'a>) -> String {
markdown::to_html(input, reps)
}
#[rustler::nif(schedule = "DirtyCpu")]
fn markdown_to_html_unsafe<'a>(input: String, reps: Term<'a>) -> String {
markdown::to_html_unsafe(input, reps)
}
// Camo NIF wrappers.
#[rustler::nif]
fn camo_image_url(input: String) -> String {
camo::image_url(input).unwrap_or_else(|| String::from(""))
}

View file

@ -0,0 +1,48 @@
use comrak::ComrakOptions;
use crate::camo;
use rustler::{MapIterator, Term};
use std::collections::HashMap;
fn common_options() -> ComrakOptions {
let mut options = ComrakOptions::default();
options.extension.autolink = true;
options.extension.table = true;
options.extension.description_lists = true;
options.extension.superscript = true;
options.extension.strikethrough = true;
options.extension.philomena = true;
options.parse.smart = true;
options.render.hardbreaks = true;
options.render.github_pre_lang = true;
options.extension.camoifier = Some(|s| camo::image_url(s).unwrap_or_else(|| String::from("")));
options
}
fn map_to_hashmap<'a>(map: Term<'a>) -> Option<HashMap<String, String>> {
Some(MapIterator::new(map)?.map(|(key, value)| {
let key: String = key.decode().unwrap_or_else(|_| String::from(""));
let value: String = value.decode().unwrap_or_else(|_| String::from(""));
(key, value)
}).collect())
}
pub fn to_html<'a>(input: String, reps: Term<'a>) -> String {
let mut options = common_options();
options.render.escape = true;
options.extension.philomena_replacements = map_to_hashmap(reps);
comrak::markdown_to_html(&input, &options)
}
pub fn to_html_unsafe<'a>(input: String, reps: Term<'a>) -> String {
let mut options = common_options();
options.render.unsafe_ = true;
options.extension.philomena_replacements = map_to_hashmap(reps);
comrak::markdown_to_html(&input, &options)
}

View file

@ -0,0 +1,145 @@
defmodule Philomena.Repo.Migrations.AddMarkdownColumns do
use Ecto.Migration
def up do
alter table("comments") do
add :body_md, :varchar, default: nil
end
alter table("messages") do
add :body_md, :varchar, default: nil
end
alter table("mod_notes") do
add :body_md, :varchar, default: nil
end
alter table("posts") do
add :body_md, :varchar, default: nil
end
alter table("badges") do
add :description_md, :varchar, default: nil
end
alter table("channels") do
add :description_md, :varchar, default: nil
end
alter table("commission_items") do
add :description_md, :varchar, default: nil
add :add_ons_md, :varchar, default: nil
end
alter table("filters") do
add :description_md, :varchar, default: nil
end
alter table("galleries") do
add :description_md, :varchar, default: nil
end
alter table("images") do
add :description_md, :varchar, default: nil
add :scratchpad_md, :varchar, default: nil
end
alter table("tags") do
add :description_md, :varchar, default: nil
end
alter table("users") do
add :description_md, :varchar, default: nil
add :scratchpad_md, :varchar, default: nil
end
alter table("dnp_entries") do
add :conditions_md, :varchar, default: nil
add :reason_md, :varchar, default: nil
add :instructions_md, :varchar, default: nil
end
alter table("commissions") do
add :information_md, :varchar, default: nil
add :contact_md, :varchar, default: nil
add :will_create_md, :varchar, default: nil
add :will_not_create_md, :varchar, default: nil
end
alter table("reports") do
add :reason_md, :varchar, default: nil
end
end
def down do
alter table("comments") do
remove :body_md
end
alter table("messages") do
remove :body_md
end
alter table("mod_notes") do
remove :body_md
end
alter table("posts") do
remove :body_md
end
alter table("badges") do
remove :description_md
end
alter table("channels") do
remove :description_md
end
alter table("commission_items") do
remove :description_md
remove :add_ons_md
end
alter table("filters") do
remove :description_md
end
alter table("galleries") do
remove :description_md
end
alter table("images") do
remove :description_md
remove :scratchpad_md
end
alter table("tags") do
remove :description_md
remove :short_description_md
remove :mod_notes_md
end
alter table("users") do
remove :description_md
remove :scratchpad_md
end
alter table("dnp_entries") do
remove :conditions_md
remove :reason_md
remove :instructions_md
end
alter table("commissions") do
remove :information_md
remove :contact_md
remove :will_create_md
remove :will_not_create_md
end
alter table("reports") do
remove :reason_md
end
end
end

View file

@ -165,7 +165,8 @@ CREATE TABLE public.badges (
created_at timestamp without time zone NOT NULL, created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL, updated_at timestamp without time zone NOT NULL,
disable_award boolean DEFAULT false NOT NULL, disable_award boolean DEFAULT false NOT NULL,
priority boolean DEFAULT false priority boolean DEFAULT false,
description_md character varying
); );
@ -227,7 +228,8 @@ CREATE TABLE public.channels (
total_viewer_minutes integer DEFAULT 0 NOT NULL, total_viewer_minutes integer DEFAULT 0 NOT NULL,
banner_image character varying, banner_image character varying,
remote_stream_id integer, remote_stream_id integer,
thumbnail_url character varying DEFAULT ''::character varying thumbnail_url character varying DEFAULT ''::character varying,
description_md character varying
); );
@ -272,7 +274,8 @@ CREATE TABLE public.comments (
edited_at timestamp without time zone, edited_at timestamp without time zone,
deletion_reason character varying DEFAULT ''::character varying NOT NULL, deletion_reason character varying DEFAULT ''::character varying NOT NULL,
destroyed_content boolean DEFAULT false, destroyed_content boolean DEFAULT false,
name_at_post_time character varying name_at_post_time character varying,
body_md character varying
); );
@ -308,7 +311,9 @@ CREATE TABLE public.commission_items (
add_ons character varying, add_ons character varying,
example_image_id integer, example_image_id integer,
created_at timestamp without time zone NOT NULL, created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL updated_at timestamp without time zone NOT NULL,
description_md character varying,
add_ons_md character varying
); );
@ -347,7 +352,11 @@ CREATE TABLE public.commissions (
will_not_create character varying, will_not_create character varying,
commission_items_count integer DEFAULT 0 NOT NULL, commission_items_count integer DEFAULT 0 NOT NULL,
created_at timestamp without time zone NOT NULL, created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL updated_at timestamp without time zone NOT NULL,
information_md character varying,
contact_md character varying,
will_create_md character varying,
will_not_create_md character varying
); );
@ -426,7 +435,10 @@ CREATE TABLE public.dnp_entries (
instructions character varying NOT NULL, instructions character varying NOT NULL,
feedback character varying NOT NULL, feedback character varying NOT NULL,
created_at timestamp without time zone NOT NULL, created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL updated_at timestamp without time zone NOT NULL,
conditions_md character varying,
reason_md character varying,
instructions_md character varying
); );
@ -539,7 +551,8 @@ CREATE TABLE public.filters (
user_count integer DEFAULT 0 NOT NULL, user_count integer DEFAULT 0 NOT NULL,
created_at timestamp without time zone NOT NULL, created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL, updated_at timestamp without time zone NOT NULL,
user_id integer user_id integer,
description_md character varying
); );
@ -666,7 +679,8 @@ CREATE TABLE public.galleries (
watcher_ids integer[] DEFAULT '{}'::integer[] NOT NULL, watcher_ids integer[] DEFAULT '{}'::integer[] NOT NULL,
watcher_count integer DEFAULT 0 NOT NULL, watcher_count integer DEFAULT 0 NOT NULL,
image_count integer DEFAULT 0 NOT NULL, image_count integer DEFAULT 0 NOT NULL,
order_position_asc boolean DEFAULT false NOT NULL order_position_asc boolean DEFAULT false NOT NULL,
description_md character varying
); );
@ -950,7 +964,9 @@ CREATE TABLE public.images (
hidden_image_key character varying, hidden_image_key character varying,
scratchpad character varying, scratchpad character varying,
hides_count integer DEFAULT 0 NOT NULL, hides_count integer DEFAULT 0 NOT NULL,
image_duration double precision image_duration double precision,
description_md character varying,
scratchpad_md character varying
); );
@ -983,7 +999,8 @@ CREATE TABLE public.messages (
created_at timestamp without time zone NOT NULL, created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL, updated_at timestamp without time zone NOT NULL,
from_id integer NOT NULL, from_id integer NOT NULL,
conversation_id integer NOT NULL conversation_id integer NOT NULL,
body_md character varying
); );
@ -1018,7 +1035,8 @@ CREATE TABLE public.mod_notes (
body text NOT NULL, body text NOT NULL,
deleted boolean DEFAULT false NOT NULL, deleted boolean DEFAULT false NOT NULL,
created_at timestamp without time zone NOT NULL, created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL updated_at timestamp without time zone NOT NULL,
body_md character varying
); );
@ -1201,7 +1219,8 @@ CREATE TABLE public.posts (
edited_at timestamp without time zone, edited_at timestamp without time zone,
deletion_reason character varying DEFAULT ''::character varying NOT NULL, deletion_reason character varying DEFAULT ''::character varying NOT NULL,
destroyed_content boolean DEFAULT false NOT NULL, destroyed_content boolean DEFAULT false NOT NULL,
name_at_post_time character varying name_at_post_time character varying,
body_md character varying
); );
@ -1242,7 +1261,8 @@ CREATE TABLE public.reports (
user_id integer, user_id integer,
admin_id integer, admin_id integer,
reportable_id integer NOT NULL, reportable_id integer NOT NULL,
reportable_type character varying NOT NULL reportable_type character varying NOT NULL,
reason_md character varying
); );
@ -1549,7 +1569,8 @@ CREATE TABLE public.tags (
created_at timestamp without time zone NOT NULL, created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL, updated_at timestamp without time zone NOT NULL,
category character varying, category character varying,
mod_notes character varying mod_notes character varying,
description_md character varying
); );
@ -1989,7 +2010,9 @@ CREATE TABLE public.users (
forced_filter_id bigint, forced_filter_id bigint,
confirmed_at timestamp(0) without time zone, confirmed_at timestamp(0) without time zone,
senior_staff boolean DEFAULT false, senior_staff boolean DEFAULT false,
bypass_rate_limits boolean DEFAULT false bypass_rate_limits boolean DEFAULT false,
description_md character varying,
scratchpad_md character varying
); );
@ -4845,4 +4868,5 @@ INSERT INTO public."schema_migrations" (version) VALUES (20201124224116);
INSERT INTO public."schema_migrations" (version) VALUES (20210121200815); INSERT INTO public."schema_migrations" (version) VALUES (20210121200815);
INSERT INTO public."schema_migrations" (version) VALUES (20210301012137); INSERT INTO public."schema_migrations" (version) VALUES (20210301012137);
INSERT INTO public."schema_migrations" (version) VALUES (20210427022351); INSERT INTO public."schema_migrations" (version) VALUES (20210427022351);
INSERT INTO public."schema_migrations" (version) VALUES (20210912171343);
INSERT INTO public."schema_migrations" (version) VALUES (20210917190346); INSERT INTO public."schema_migrations" (version) VALUES (20210917190346);