summaryrefslogtreecommitdiff
path: root/lib/tmpl.ex
blob: 1470603c80832f8b9d022f5245c904fb2e347bc4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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