defmodule Tmpl do require Logger defmodule Filter do use Liquex.Filter def repeat(text, val, _) do String.duplicate(text, val) end def rrepeat(text, max, _) do String.duplicate(text, :random.uniform(max)) end def rrepeat(text, var) do rrepeat(text, 20, var) end def bold(text, %{variables: variables}) do unless Map.get(variables, "_no_format") || Map.get(variables, "_no_bold") do <<2>> <> text <> <<2>> else text end end @colors [:white, :black, :blue, :green, :red, :brown, :purple, :orange, :yellow, :light_green, :cyan, :light_blue, :pink, :grey, :light_grey] for {color, index} <- Enum.with_index(@colors) do code = 48+index def color_code(unquote(color)) do unquote(code) end def unquote(color)(text, %{variables: variables}) do unless Map.get(variables, "_no_format") || Map.get(variables, "_no_colors") do <<3, unquote(code)>> <> text <> <<3>> else text end end end def account_nick(%{"id" => id, "name" => name}, %{variables: %{"message" => %{"network" => network}}}) do if user = IRC.UserTrack.find_by_account(network, %IRC.Account{id: id}) do user.nick else name end end def account_nick(val, ctx) do "{{account_nick}}" end end def render(template, msg = %IRC.Message{}, context \\ %{}, safe \\ true) do do_render(template, Map.put(context, "message", msg), safe) end defp do_render(template, context, safe) when is_binary(template) do case Liquex.parse(template) do {:ok, template_ast} -> do_render(template_ast, context, safe) {:error, err, pos} -> Logger.debug("Liquid error: #{pos} - #{inspect template}") "[liquid ast error (at #{pos}): #{inspect err}]" end end defp do_render(template_ast, context, safe) when is_list(template_ast) do context = Liquex.Context.new(mapify(context, safe)) |> Map.put(:filter_module, Tmpl.Filter) {content, _context} = Liquex.render(template_ast, context) to_string(content) rescue e -> Logger.error("Liquid error: #{inspect e}") "[liquid rendering error]" end defp mapify(struct = %{__struct__: _}, safe) do mapify(Map.from_struct(struct), safe) end defp mapify(map = %{}, safe) do map |> Enum.reduce(Map.new, fn({k,v}, acc) -> k = to_string(k) if safe?(k, safe) do if v = mapify(v, safe) do Map.put(acc, k, v) else acc end else acc end end) end defp mapify(fun, _) when is_function(fun) do nil end defp mapify(atom, _) when is_atom(atom) do to_string(atom) end defp mapify(v, _) do v end defp safe?(_, false) do true end defp safe?("token", true), do: false defp safe?("password", true), do: false defp safe?(_, true), do: true end