summaryrefslogtreecommitdiff
path: root/lib/lsg_web
diff options
context:
space:
mode:
authorhref <href@random.sh>2020-07-07 21:39:10 +0200
committerhref <href@random.sh>2020-07-07 21:39:51 +0200
commitd6ee134a5957e299c3ad59011df320b3c41e6e61 (patch)
tree29567e6635466f8a3415a935b3cc8a777019f5bc /lib/lsg_web
parentbleh (diff)
pouet
Diffstat (limited to 'lib/lsg_web')
-rw-r--r--lib/lsg_web/channels/user_socket.ex2
-rw-r--r--lib/lsg_web/context_plug.ex81
-rw-r--r--lib/lsg_web/controllers/alcoolog_controller.ex56
-rw-r--r--lib/lsg_web/controllers/irc_auth_sse_controller.ex66
-rw-r--r--lib/lsg_web/controllers/irc_controller.ex27
-rw-r--r--lib/lsg_web/controllers/network_controller.ex11
-rw-r--r--lib/lsg_web/controllers/page_controller.ex50
-rw-r--r--lib/lsg_web/controllers/sms_controller.ex10
-rw-r--r--lib/lsg_web/controllers/untappd_controller.ex18
-rw-r--r--lib/lsg_web/endpoint.ex2
-rw-r--r--lib/lsg_web/router.ex35
-rw-r--r--lib/lsg_web/templates/alcoolog/auth.html.eex39
-rw-r--r--lib/lsg_web/templates/alcoolog/index.html.eex61
-rw-r--r--lib/lsg_web/templates/irc/index.html.eex30
-rw-r--r--lib/lsg_web/templates/irc/txt.html.eex7
-rw-r--r--lib/lsg_web/templates/irc/txts.html.eex14
-rw-r--r--lib/lsg_web/templates/layout/app.html.eex16
-rw-r--r--lib/lsg_web/templates/network/index.html.eex1
-rw-r--r--lib/lsg_web/templates/page/user.html.eex38
-rw-r--r--lib/lsg_web/views/layout_view.ex66
-rw-r--r--lib/lsg_web/views/network_view.ex4
21 files changed, 520 insertions, 114 deletions
diff --git a/lib/lsg_web/channels/user_socket.ex b/lib/lsg_web/channels/user_socket.ex
index 6fedf18..691a26c 100644
--- a/lib/lsg_web/channels/user_socket.ex
+++ b/lib/lsg_web/channels/user_socket.ex
@@ -5,7 +5,7 @@ defmodule LSGWeb.UserSocket do
# channel "room:*", LSGWeb.RoomChannel
## Transports
- transport :websocket, Phoenix.Transports.WebSocket
+ #transport :websocket, Phoenix.Transports.WebSocket
# transport :longpoll, Phoenix.Transports.LongPoll
# Socket params are passed from the client and can
diff --git a/lib/lsg_web/context_plug.ex b/lib/lsg_web/context_plug.ex
new file mode 100644
index 0000000..7896ace
--- /dev/null
+++ b/lib/lsg_web/context_plug.ex
@@ -0,0 +1,81 @@
+defmodule LSGWeb.ContextPlug do
+ import Plug.Conn
+ import Phoenix.Controller
+
+ def init(opts \\ []) do
+ opts || []
+ end
+
+ def call(conn, opts) do
+ account = with \
+ {:account, account_id} when is_binary(account_id) <- {:account, get_session(conn, :account)},
+ {:account, account} when not is_nil(account) <- {:account, IRC.Account.get(account_id)}
+ do
+ account
+ else
+ _ -> nil
+ end
+
+ network = Map.get(conn.params, "network")
+ network = if network == "-", do: nil, else: network
+
+ conns = IRC.Connection.get_network(network)
+ chan = if c = Map.get(conn.params, "chan") do
+ LSGWeb.reformat_chan(c)
+ end
+ chan_conn = IRC.Connection.get_network(network, chan)
+
+ memberships = if account do
+ IRC.Membership.of_account(account)
+ end
+
+ auth_required = cond do
+ Keyword.get(opts, :restrict) == :public -> false
+ account == nil -> true
+ network == nil -> false
+ Keyword.get(opts, :restrict) == :logged_in -> false
+ network && chan ->
+ !Enum.member?(memberships, {network, chan})
+ network ->
+ !Enum.any?(memberships, fn({n, _}) -> n == network end)
+ end
+
+ bot = cond do
+ network && chan && chan_conn -> chan_conn.nick
+ network && conns -> conns.nick
+ true -> nil
+ end
+
+
+ cond do
+ account && auth_required ->
+ conn
+ |> put_status(404)
+ |> text("Page not found")
+ |> halt()
+ auth_required ->
+ conn
+ |> put_status(403)
+ |> render(LSGWeb.AlcoologView, "auth.html", bot: bot, no_header: true, network: network)
+ |> halt()
+ (network && !conns) ->
+ conn
+ |> put_status(404)
+ |> text("Page not found")
+ |> halt()
+ (chan && !chan_conn) ->
+ conn
+ |> put_status(404)
+ |> text("Page not found")
+ |> halt()
+ true ->
+ conn = conn
+ |> assign(:network, network)
+ |> assign(:chan, chan)
+ |> assign(:bot, bot)
+ |> assign(:account, account)
+ |> assign(:memberships, memberships)
+ end
+ end
+
+end
diff --git a/lib/lsg_web/controllers/alcoolog_controller.ex b/lib/lsg_web/controllers/alcoolog_controller.ex
index 9d5d9d9..b88faa3 100644
--- a/lib/lsg_web/controllers/alcoolog_controller.ex
+++ b/lib/lsg_web/controllers/alcoolog_controller.ex
@@ -2,9 +2,12 @@ defmodule LSGWeb.AlcoologController do
use LSGWeb, :controller
require Logger
- def index(conn, %{"channel" => channel}) do
- case LSG.Token.lookup(channel) do
- {:ok, obj} -> index(conn, obj)
+ plug LSGWeb.ContextPlug when action not in [:token]
+ plug LSGWeb.ContextPlug, [restrict: :public] when action in [:token]
+
+ def token(conn, %{"token" => token}) do
+ case LSG.Token.lookup(token) do
+ {:ok, {:alcoolog, :index, network, channel}} -> index(conn, nil, network, channel)
err ->
Logger.debug("AlcoologControler: token #{inspect err} invalid")
conn
@@ -13,8 +16,31 @@ defmodule LSGWeb.AlcoologController do
end
end
- def index(conn, {:alcoolog, :index, channel}) do
- aday = 7*((24 * 60)*60)
+ def index(conn = %{assigns: %{account: account}}, %{"network" => network, "chan" => channel}) do
+ index(conn, account, network, LSGWeb.reformat_chan(channel))
+ end
+
+ def index(conn = %{assigns: %{account: account}}, _) do
+ index(conn, account, nil, nil)
+ end
+
+ #def index(conn, params) do
+ # network = Map.get(params, "network")
+ # chan = if c = Map.get(params, "chan") do
+ # LSGWeb.reformat_chan(c)
+ # end
+ # irc_conn = if network do
+ # IRC.Connection.get_network(network, chan)
+ # end
+ # bot = if(irc_conn, do: irc_conn.nick)#
+ #
+ # conn
+ # |> put_status(403)
+ # |> render("auth.html", network: network, channel: chan, irc_conn: conn, bot: bot)
+ #end
+
+ def index(conn, account, network, channel) do
+ aday = 18*((24 * 60)*60)
now = DateTime.utc_now()
before = now
|> DateTime.add(-aday, :second)
@@ -27,22 +53,28 @@ defmodule LSGWeb.AlcoologController do
], [:"$_"]}
]
- nicks_in_channel = IRC.UserTrack.channel(channel)
- |> Enum.map(fn({_, nick, _, _, _, _, _}) -> String.downcase(nick) end)
# tuple ets: {{nick, date}, volumes, current, nom, commentaire}
+ members = IRC.Membership.expanded_members_or_friends(account, network, channel)
+ members_ids = Enum.map(members, fn({account, _, nick}) -> account.id end)
+ member_names = Enum.reduce(members, %{}, fn({account, _, nick}, acc) -> Map.put(acc, account.id, nick) end)
drinks = :ets.select(LSG.IRC.AlcoologPlugin.ETS, match)
- #|> Enum.filter(fn({{nick, _}, _, _, _, _}) -> Enum.member?(nicks_in_channel, nick) end)
- |> Enum.sort_by(fn({{_, ts}, _, _, _, _}) -> ts end, &>/2)
+ |> Enum.filter(fn({{account, _}, _, _, _, _}) -> Enum.member?(members_ids, account) end)
+ |> Enum.map(fn({{account, _}, _, _, _, _} = object) -> {object, Map.get(member_names, account)} end)
+ |> Enum.sort_by(fn({{{_, ts}, _, _, _, _}, _}) -> ts end, &>/2)
- stats = LSG.IRC.AlcoologPlugin.get_channel_statistics(channel)
+ stats = LSG.IRC.AlcoologPlugin.get_channel_statistics(account, network, channel)
- top = Enum.reduce(drinks, %{}, fn({{nick, _}, vol, _, _, _}, acc) ->
+ top = Enum.reduce(drinks, %{}, fn({{{account_id, _}, vol, _, _, _}, _}, acc) ->
+ nick = Map.get(member_names, account_id)
all = Map.get(acc, nick, 0)
Map.put(acc, nick, all + vol)
end)
|> Enum.sort_by(fn({_nick, count}) -> count end, &>/2)
# {date, single_peak}
- render(conn, "index.html", channel: channel, drinks: drinks, top: top, stats: stats)
+ #
+ conn
+ |> assign(:title, "alcoolog")
+ |> render("index.html", network: network, channel: channel, drinks: drinks, top: top, stats: stats)
end
end
diff --git a/lib/lsg_web/controllers/irc_auth_sse_controller.ex b/lib/lsg_web/controllers/irc_auth_sse_controller.ex
new file mode 100644
index 0000000..c39a866
--- /dev/null
+++ b/lib/lsg_web/controllers/irc_auth_sse_controller.ex
@@ -0,0 +1,66 @@
+defmodule LSGWeb.IrcAuthSseController do
+ use LSGWeb, :controller
+ require Logger
+
+ @ping_interval 20_000
+ @expire_delay :timer.minutes(3)
+
+ def sse(conn, params) do
+ perks = if uri = Map.get(params, "redirect_to") do
+ {:redirect, uri}
+ else
+ nil
+ end
+ token = String.downcase(EntropyString.random_string(65))
+ conn
+ |> assign(:token, token)
+ |> assign(:perks, perks)
+ |> put_resp_header("X-Accel-Buffering", "no")
+ |> put_resp_header("content-type", "text/event-stream")
+ |> send_chunked(200)
+ |> subscribe()
+ |> send_sse_message("token", token)
+ |> sse_loop
+ end
+
+ def subscribe(conn) do
+ :timer.send_interval(@ping_interval, {:event, :ping})
+ :timer.send_after(@expire_delay, {:event, :expire})
+ {:ok, _} = Registry.register(IRC.PubSub, "message:private", [])
+ conn
+ end
+
+ def sse_loop(conn) do
+ {type, event, exit} = receive do
+ {:event, :ping} -> {"ping", "ping", false}
+ {:event, :expire} -> {"expire", "expire", true}
+ {:irc, :text, %{account: account, text: token} = m} ->
+ if String.downcase(String.trim(token)) == conn.assigns.token do
+ path = LSG.AuthToken.new_path(account.id, conn.assigns.perks)
+ m.replyfun.("ok!")
+ {"authenticated", path, true}
+ else
+ {nil, nil, false}
+ end
+ _ -> {nil, nil, false}
+ end
+
+ conn = if type do
+ send_sse_message(conn, type, event)
+ else
+ conn
+ end
+
+ if exit do
+ conn
+ else
+ sse_loop(conn)
+ end
+ end
+
+ defp send_sse_message(conn, type, data) do
+ {:ok, conn} = chunk(conn, "event: #{type}\ndata: #{data}\n\n")
+ conn
+ end
+
+end
diff --git a/lib/lsg_web/controllers/irc_controller.ex b/lib/lsg_web/controllers/irc_controller.ex
index 022807d..e0bf24d 100644
--- a/lib/lsg_web/controllers/irc_controller.ex
+++ b/lib/lsg_web/controllers/irc_controller.ex
@@ -1,13 +1,21 @@
defmodule LSGWeb.IrcController do
use LSGWeb, :controller
- def index(conn, _) do
- commands = for mod <- (Application.get_env(:lsg, :irc)[:plugins] ++ Application.get_env(:lsg, :irc)[:handlers]) do
+ plug LSGWeb.ContextPlug
+
+ def index(conn, params) do
+ network = Map.get(params, "network")
+ channel = if c = Map.get(params, "channel"), do: LSGWeb.reformat_chan(c)
+ commands = for mod <- ([IRC.Account.AccountPlugin] ++ Application.get_env(:lsg, :irc)[:plugins] ++ Application.get_env(:lsg, :irc)[:handlers]) do
identifier = Module.split(mod) |> List.last |> String.replace("Plugin", "") |> Macro.underscore
{identifier, mod.irc_doc()}
end
|> Enum.reject(fn({_, i}) -> i == nil end)
- render conn, "index.html", commands: commands
+ members = cond do
+ network -> IRC.Membership.expanded_members_or_friends(conn.assigns.account, network, channel)
+ true -> IRC.Membership.of_account(conn.assigns.account)
+ end
+ render conn, "index.html", network: network, commands: commands, channel: channel, members: members
end
def txt(conn, %{"name" => name}) do
@@ -33,13 +41,22 @@ defmodule LSGWeb.IrcController do
doc = LSG.IRC.TxtPlugin.irc_doc()
data = data()
lines = Enum.reduce(data, 0, fn({_, lines}, acc) -> acc + Enum.count(lines) end)
- render conn, "txts.html", data: data, doc: doc, files: Enum.count(data), lines: lines
+ conn
+ |> assign(:title, "txt")
+ |> render("txts.html", data: data, doc: doc, files: Enum.count(data), lines: lines)
end
defp do_txt(conn, txt) do
data = data()
+ base_url = cond do
+ conn.assigns[:chan] -> "/#{conn.assigns.network}/#{LSGWeb.format_chan(conn.assigns.chan)}"
+ true -> "/-"
+ end
if Map.has_key?(data, txt) do
- render(conn, "txt.html", name: txt, data: data[txt], doc: nil)
+ conn
+ |> assign(:breadcrumbs, [{"txt", "#{base_url}/txt"}])
+ |> assign(:title, "#{txt}.txt")
+ |> render("txt.html", name: txt, data: data[txt], doc: nil)
else
conn
|> put_status(404)
diff --git a/lib/lsg_web/controllers/network_controller.ex b/lib/lsg_web/controllers/network_controller.ex
new file mode 100644
index 0000000..537c2f6
--- /dev/null
+++ b/lib/lsg_web/controllers/network_controller.ex
@@ -0,0 +1,11 @@
+defmodule LSGWeb.NetworkController do
+ use LSGWeb, :controller
+ plug LSGWeb.ContextPlug
+
+ def index(conn, %{"network" => network}) do
+ conn
+ |> assign(:title, network)
+ |> render("index.html")
+ end
+
+end
diff --git a/lib/lsg_web/controllers/page_controller.ex b/lib/lsg_web/controllers/page_controller.ex
index b356b9c..a87cf1d 100644
--- a/lib/lsg_web/controllers/page_controller.ex
+++ b/lib/lsg_web/controllers/page_controller.ex
@@ -1,12 +1,35 @@
defmodule LSGWeb.PageController do
use LSGWeb, :controller
- def index(conn, _params) do
- render conn, "index.html"
+ plug LSGWeb.ContextPlug when action not in [:token]
+ plug LSGWeb.ContextPlug, [restrict: :public] when action in [:token]
+
+ def token(conn, %{"token" => token}) do
+ with \
+ {:ok, account, perks} <- LSG.AuthToken.lookup(token)
+ do
+ IO.puts("Authenticated account #{inspect account}")
+ conn = put_session(conn, :account, account)
+ case perks do
+ nil -> redirect(conn, to: "/")
+ {:redirect, path} -> redirect(conn, to: path)
+ {:external_redirect, url} -> redirect(conn, external: url)
+ end
+ else
+ z ->
+ IO.inspect(z)
+ text(conn, "Error: invalid or expired token")
+ end
end
- def api(conn, _params) do
- render conn, "api.html"
+ def index(conn = %{assigns: %{account: account}}, _) do
+ memberships = IRC.Membership.of_account(account)
+ users = IRC.UserTrack.find_by_account(account)
+ metas = IRC.Account.get_all_meta(account)
+ predicates = IRC.Account.get_predicates(account)
+ conn
+ |> assign(:title, account.name)
+ |> render("user.html", users: users, memberships: memberships, metas: metas, predicates: predicates)
end
def irc(conn, _) do
@@ -16,16 +39,15 @@ defmodule LSGWeb.PageController do
render conn, "irc.html", bot_helps: bot_helps
end
- def icecast(conn, _params) do
- conn
- |> json(LSG.IcecastAgent.get)
- end
-
- def widget(conn, options) do
- icecast = LSG.IcecastAgent.get
- conn
- |> put_layout(false)
- |> render("widget.html", icecast: icecast)
+ def authenticate(conn, _) do
+ with \
+ {:account, account_id} when is_binary(account_id) <- {:account, get_session(conn, :account)},
+ {:account, account} when not is_nil(account) <- {:account, IRC.Account.get(account_id)}
+ do
+ assign(conn, :account, account)
+ else
+ _ -> conn
+ end
end
end
diff --git a/lib/lsg_web/controllers/sms_controller.ex b/lib/lsg_web/controllers/sms_controller.ex
new file mode 100644
index 0000000..00c6352
--- /dev/null
+++ b/lib/lsg_web/controllers/sms_controller.ex
@@ -0,0 +1,10 @@
+defmodule LSGWeb.SmsController do
+ use LSGWeb, :controller
+ require Logger
+
+ def ovh_callback(conn, %{"senderid" => from, "message" => message}) do
+ spawn(fn() -> LSG.IRC.SmsPlugin.incoming(from, String.trim(message)) end)
+ text(conn, "")
+ end
+
+end
diff --git a/lib/lsg_web/controllers/untappd_controller.ex b/lib/lsg_web/controllers/untappd_controller.ex
new file mode 100644
index 0000000..1c3ceb1
--- /dev/null
+++ b/lib/lsg_web/controllers/untappd_controller.ex
@@ -0,0 +1,18 @@
+defmodule LSGWeb.UntappdController do
+ use LSGWeb, :controller
+
+ def callback(conn, %{"code" => code}) do
+ with \
+ {:account, account_id} when is_binary(account_id) <- {:account, get_session(conn, :account)},
+ {:account, account} when not is_nil(account) <- {:account, IRC.Account.get(account_id)},
+ {:ok, auth_token} <- Untappd.auth_callback(code)
+ do
+ IRC.Account.put_meta(account, "untappd-token", auth_token)
+ text(conn, "OK!")
+ else
+ {:account, _} -> text(conn, "Error: account not found")
+ :error -> text(conn, "Error: untappd authentication failed")
+ end
+ end
+
+end
diff --git a/lib/lsg_web/endpoint.ex b/lib/lsg_web/endpoint.ex
index 2d0a6be..e89dc12 100644
--- a/lib/lsg_web/endpoint.ex
+++ b/lib/lsg_web/endpoint.ex
@@ -1,7 +1,7 @@
defmodule LSGWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :lsg
- socket "/socket", LSGWeb.UserSocket
+ socket "/socket", LSGWeb.UserSocket, websocket: true
# Serve at "/" the static files from "priv/static" directory.
#
diff --git a/lib/lsg_web/router.ex b/lib/lsg_web/router.ex
index a834083..de7fafb 100644
--- a/lib/lsg_web/router.ex
+++ b/lib/lsg_web/router.ex
@@ -3,8 +3,8 @@ defmodule LSGWeb.Router do
pipeline :browser do
plug :accepts, ["html", "txt"]
- #plug :fetch_session
- #plug :fetch_flash
+ plug :fetch_session
+ plug :fetch_flash
#plug :protect_from_forgery
#plug :put_secure_browser_headers
end
@@ -13,22 +13,33 @@ defmodule LSGWeb.Router do
plug :accepts, ["json", "sse"]
end
+ scope "/api", LSGWeb do
+ pipe_through :api
+ get "/irc-auth.sse", IrcAuthSseController, :sse
+ post "/sms/callback/Ovh", SmsController, :ovh_callback, as: :sms
+ end
+
scope "/", LSGWeb do
pipe_through :browser
get "/", PageController, :index
get "/embed/widget", PageController, :widget
get "/api", PageController, :api
- get "/irc", IrcController, :index
- get "/irc/txt", IrcController, :txt
- get "/irc/txt/:name", IrcController, :txt
- get "/irc/alcoolog/:channel", AlcoologController, :index
- get "/irc/alcoolog/~/:nick", AlcoologController, :nick
+ get "/login/irc/:token", PageController, :token, as: :login
+ get "/api/untappd/callback", UntappdController, :callback, as: :untappd_callback
+ get "/-", IrcController, :index
+ get "/-/txt", IrcController, :txt
+ get "/-/txt/:name", IrcController, :txt
+ get "/-/alcoolog", AlcoologController, :index
+ get "/-/alcoolog/~/:account_name", AlcoologController, :index
+ get "/:network", NetworkController, :index
+ get "/:network/:chan", IrcController, :index
+ get "/:network/:chan/txt", IrcController, :txt
+ get "/:network/:chan/txt/:name", IrcController, :txt
+ get "/:network/:channel/preums", IrcController, :preums
+ get "/:network/:chan/alcoolog", AlcoologController, :index
+ get "/:network/:chan/alcoolog/t/:token", AlcoologController, :token
+ get "/:network/alcoolog/~/:nick", AlcoologController, :nick
end
- scope "/api", LSGWeb do
- pipe_through :api
- get "/icecast.json", PageController, :icecast
- get "/icecast.sse", IcecastSseController, :sse
- end
end
diff --git a/lib/lsg_web/templates/alcoolog/auth.html.eex b/lib/lsg_web/templates/alcoolog/auth.html.eex
new file mode 100644
index 0000000..af6db53
--- /dev/null
+++ b/lib/lsg_web/templates/alcoolog/auth.html.eex
@@ -0,0 +1,39 @@
+<h1>authentication</h1>
+
+<div id="authenticator">
+ <p>
+ <%= if @bot, do: "Send this to #{@bot} on #{@network}:", else: "Find your bot nickname and send:" %><br /><br />
+ <strong>/msg <%= @bot || "the-bot-nickname" %> web</strong>
+ <br /><br />
+ ... then come back to this address.
+ </p>
+</div>
+
+<script type="text/javascript">
+ var authSse = new EventSource("/api/irc-auth.sse?redirect_to=" + window.location.pathname);
+ authSse.addEventListener("token", function(event) {
+ html = "<%= if @bot, do: "Send this to #{@bot} on #{@network}:", else: "Find your bot nickname and send:" %><br /><br /><strong>/msg <%= @bot || "the-bot-nickname" %> "+event.data+"</strong>";
+ elem = document.getElementById("authenticator");
+ elem.innerHTML = html;
+ });
+ authSse.addEventListener("authenticated", function(event) {
+ elem = document.getElementById("authenticator");
+ elem.innerHTML = "<strong>success, redirecting...</strong>";
+ window.keepInner = true;
+ window.location.pathname = event.data;
+ });
+ authSse.addEventListener("expire", function(event) {
+ elem = document.getElementById("authenticator");
+ elem.innerHTML = "<strong>authentication expired</strong>";
+ window.keepInner = true;
+ });
+ authSse.onerror = function() {
+ authSse.close();
+ if (!window.keepInner) {
+ elem = document.getElementById("authenticator");
+ elem.innerHTML = "<strong>server closed connection :(</strong>";
+ }
+ };
+
+</script>
+
diff --git a/lib/lsg_web/templates/alcoolog/index.html.eex b/lib/lsg_web/templates/alcoolog/index.html.eex
index 507be71..e656e64 100644
--- a/lib/lsg_web/templates/alcoolog/index.html.eex
+++ b/lib/lsg_web/templates/alcoolog/index.html.eex
@@ -1,16 +1,12 @@
<style type="text/css">
-h1 small {
- font-size: 14px;
-}
ol li {
margin-bottom: 5px
}
</style>
-<h1>
- <small><a href="/irc"><%= Keyword.get(Application.get_env(:lsg, :irc), :name, "ircbot") %></a> &rsaquo; </small><br/>
- alcoolog <%= @channel %>
-</h1>
+<%= if @stats == [] do %>
+ </strong><i>:o personne ne boit</i></strong>
+<% end %>
<ul>
<%= for {nick, status} <- @stats do %>
@@ -28,28 +24,35 @@ ol li {
<% end %>
</ul>
-<p>
- top consommateur par volume, les 7 derniers jours: <%= Enum.intersperse(for({nick, count} <- @top, do: "#{nick}: #{Float.round(count,4)}"), ", ") %>
-</p>
+<%= if @stats == %{} do %>
+ <strong><i>... et personne n'a bu :o :o :o</i></strong>
+<% else %>
+ <p>
+ top consommateur par volume, les 7 derniers jours: <%= Enum.intersperse(for({nick, count} <- @top, do: "#{nick}: #{Float.round(count,4)}"), ", ") %>
+ </p>
-<table class="table">
- <thead>
- <tr>
- <th scope="col">date</th>
- <th scope="col">nick</th>
- <th scope="col">points</th>
- <th scope="col">nom</th>
- </tr>
- </thead>
- <tbody>
- <%= for {{nick, date}, points, _, nom, comment} <- @drinks do %>
- <% date = DateTime.from_unix!(date, :millisecond) %>
- <th scope="row"><%= LSGWeb.LayoutView.format_time(date, false) %></th>
- <td><%= nick %></td>
- <td><%= Float.round(points+0.0, 5) %></td>
- <td><%= nom||"" %> <%= comment||"" %></td>
+ <table class="table">
+ <thead>
+ <tr>
+ <th scope="col">date</th>
+ <th scope="col">nick</th>
+ <th scope="col">points</th>
+ <th scope="col">nom</th>
</tr>
- <% end %>
- </tbody>
-</table>
+ </thead>
+ <tbody>
+ <%= for {{{account, date}, points, _, nom, comment}, nick} <- @drinks do %>
+ <% date = DateTime.from_unix!(date, :millisecond) %>
+ <th scope="row"><%= LSGWeb.LayoutView.format_time(date, false) %></th>
+ <td><%= nick %></td>
+ <td><%= Float.round(points+0.0, 5) %></td>
+ <td><%= nom||"" %> <%= comment||"" %></td>
+ </tr>
+ <% end %>
+ </tbody>
+ </table>
+<% end %>
+<%= if @conn.assigns.account && (@network || @channel) do %>
+ <%= link("alcoolog global", to: alcoolog_path(@conn, :index)) %>
+<% end %>
diff --git a/lib/lsg_web/templates/irc/index.html.eex b/lib/lsg_web/templates/irc/index.html.eex
index f127101..9e4f724 100644
--- a/lib/lsg_web/templates/irc/index.html.eex
+++ b/lib/lsg_web/templates/irc/index.html.eex
@@ -1,23 +1,4 @@
<style type="text/css">
-h1 small {
- font-size: 14px;
-}
-</style>
-
-<h1><%= Keyword.get(Application.get_env(:lsg, :irc), :name, "ircbot") %></h1>
-
-<!--<p>
-Serveur IRC: <a href="irc://irc.quakenet.org/lsg">irc.quakenet.org #lsg</a>.
-&nbsp;Matrix: <a href="https://matrix.random.sh/riot/#rooms/#lsg:random.sh">#lsg:random.sh</a>.
-<br />
-<a href="https://115ans.net/irc/">Webchat</a>.
-<br />
-<a href="/irc/stats/">Statistiques</a>.
-</del>
-</p>-->
-
-
-<style type="text/css">
.help-entry h1 {
font-size: 18px;
}
@@ -29,15 +10,22 @@ Serveur IRC: <a href="irc://irc.quakenet.org/lsg">irc.quakenet.org #lsg</a>.
<p>
<% list = for {identifier, _} <- @commands do %>
<% name = String.replace(identifier, "_", " ") %>
- <%= link(name, to: "##{identifier}") #raw("<a href='##{identifier}'>#{name}</a>") %>
+ <%= link(name, to: "##{identifier}") %>
<% end %>
<small><%= Enum.intersperse(list, " - ") %></small>
</p>
+<%= if @members != [] do %>
+<% users = for {_acc, user, nick} <- @members, do: if(user, do: nick, else: content_tag(:i, nick)) %>
+<%= for u <- Enum.intersperse(users, ", ") do %>
+ <%= u %>
+<% end %>
+<% end %>
+
<div class="irchelps">
<%= for {identifier, help} <- @commands do %>
<%= if help do %>
- <div class="help-entry" id="<%= identifier %>"><%= help |> Earmark.as_html! |> raw() %></div>
+ <div class="help-entry" id="<%= identifier %>"><%= LSGWeb.LayoutView.liquid_markdown(@conn, help) %></div>
<% end %>
<% end %>
</div>
diff --git a/lib/lsg_web/templates/irc/txt.html.eex b/lib/lsg_web/templates/irc/txt.html.eex
index 5b31320..e9df681 100644
--- a/lib/lsg_web/templates/irc/txt.html.eex
+++ b/lib/lsg_web/templates/irc/txt.html.eex
@@ -1,16 +1,9 @@
<style type="text/css">
-h1 small {
- font-size: 14px;
-}
ol li {
margin-bottom: 5px
}
</style>
-<h1>
- <small><a href="/irc"><%= Keyword.get(Application.get_env(:lsg, :irc), :name, "ircbot") %></a> &rsaquo; <a href="/irc/txt">txt</a> &rsaquo;</small><br/>
- <%= @name %>.txt</h1>
-
<ol>
<%= for {txt, id} <- Enum.with_index(@data) do %>
<li id="<%= @name %>-<%= id %>"><%= txt %></li>
diff --git a/lib/lsg_web/templates/irc/txts.html.eex b/lib/lsg_web/templates/irc/txts.html.eex
index 28d0220..5971ffa 100644
--- a/lib/lsg_web/templates/irc/txts.html.eex
+++ b/lib/lsg_web/templates/irc/txts.html.eex
@@ -5,13 +5,7 @@
.help-entry h2 {
font-size: 16px;
}
-h1 small {
- font-size: 14px;
-}
</style>
-<h1>
- <small><a href="/irc"><%= Keyword.get(Application.get_env(:lsg, :irc), :name, "ircbot") %></a> &rsaquo; </small><br/>
- txt</h1>
<p><strong><%= @lines %></strong> lignes dans <strong><%= @files %></strong> fichiers.
<a href="#help">Aide</a>.
@@ -19,9 +13,13 @@ h1 small {
<ul>
<%= for {txt, data} <- @data do %>
- <li><a href="/irc/txt/<%= txt %>"><%= txt %></a> <i>(<%= Enum.count(data) %>)</i></li>
+ <% base_url = cond do
+ @conn.assigns[:chan] -> "/#{@conn.assigns.network}/#{LSGWeb.format_chan(@conn.assigns.chan)}"
+ true -> "/-"
+ end %>
+ <li><a href="<%= base_url %>/txt/<%= txt %>"><%= txt %></a> <i>(<%= Enum.count(data) %>)</i></li>
<% end %>
</ul>
-<div class="help-entry" id="help"><%= @doc |> Earmark.as_html! |> raw() %></div>
+<div class="help-entry" id="help"><%= LSGWeb.LayoutView.liquid_markdown(@conn, @doc) %></div>
diff --git a/lib/lsg_web/templates/layout/app.html.eex b/lib/lsg_web/templates/layout/app.html.eex
index 4c2ad44..1871e8b 100644
--- a/lib/lsg_web/templates/layout/app.html.eex
+++ b/lib/lsg_web/templates/layout/app.html.eex
@@ -1,16 +1,32 @@
<!DOCTYPE html>
<html lang="en">
<head>
+ <%= page_title(@conn) %>
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow, nosnippet">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta name="robots" content="noindex, noarchive, nofollow, nosnippet" />
+ <title><%= Map.get(assigns, :title, "") %></title>
<link rel="stylesheet" href="<%= static_path(@conn, "/assets/css/app.css") %>">
</head>
<body>
<div class="container">
<main role="main">
+ <%= if !@conn.assigns[:no_header] do %>
+ <h1>
+ <small style="font-size: 14px;">
+ <a href="/"><%= Keyword.get(Application.get_env(:lsg, :irc), :name, "ircbot") %></a>
+ <%= if @conn.assigns[:account], do: @conn.assigns.account.name %>
+ &rsaquo;
+ <%= if n = @conn.assigns[:network] do %><a href="/<%= n %>"><%= n %></a> &rsaquo; <% end %>
+ <%= if c = @conn.assigns[:chan] do %><a href="/<%= @conn.assigns.network %>/<%= LSGWeb.format_chan(c) %>"><%= c %></a> &rsaquo; <% end %>
+ <%= for({name, href} <- @conn.assigns[:breadcrumbs]||[], do: [link(name, to: href), raw(" &rsaquo; ")]) %>
+ </small><br />
+ <%= @conn.assigns[:title] || @conn.assigns[:chan] || @conn.assigns[:network] %>
+ </h1>
+ <% end %>
<%= render @view_module, @view_template, assigns %>
</main>
</div>
diff --git a/lib/lsg_web/templates/network/index.html.eex b/lib/lsg_web/templates/network/index.html.eex
new file mode 100644
index 0000000..fc024dd
--- /dev/null
+++ b/lib/lsg_web/templates/network/index.html.eex
@@ -0,0 +1 @@
+pouet
diff --git a/lib/lsg_web/templates/page/user.html.eex b/lib/lsg_web/templates/page/user.html.eex
new file mode 100644
index 0000000..8a043a0
--- /dev/null
+++ b/lib/lsg_web/templates/page/user.html.eex
@@ -0,0 +1,38 @@
+<ul>
+ <li><%= link("Help", to: "/-") %></li>
+</ul>
+
+<h2>channels</h2>
+<ul>
+ <%= for {net, channel} <- @memberships do %>
+ <li>
+ <% url = LSGWeb.Router.Helpers.irc_path(LSGWeb.Endpoint, :index, net, LSGWeb.format_chan(channel)) %>
+ <%= link([net, ": ", content_tag(:strong, channel)], to: url) %>
+ </li>
+ <% end %>
+</ul>
+
+<h2>connections</h2>
+<ul>
+ <%= for user <- @users do %>
+ <li>
+ <strong><%= user.network %></strong>: <strong><%= user.nick %></strong>!<%= user.username %>@<%= user.host %> <i><%= user.realname %></i><br />
+ <%= Enum.join(Enum.intersperse(Enum.map(user.privileges, fn({c, _}) -> c end), ", ")) %>
+ </li>
+ <% end %>
+</ul>
+
+<h2>account</h2>
+<ul>
+ <li>account-id: <%= @conn.assigns.account.id %></li>
+ <%= for {k, v} <- @metas do %>
+ <li><%= k %>: <%= to_string(v) %></li>
+ <% end %>
+</ul>
+
+<strong>irc auths:</strong>
+<ul>
+ <%= for {net, {predicate, v}} <- @predicates do %>
+ <li><%= net %>: <%= to_string(predicate) %>, <%= v %></li>
+ <% end %>
+</ul>
diff --git a/lib/lsg_web/views/layout_view.ex b/lib/lsg_web/views/layout_view.ex
index 956d703..b28d3c5 100644
--- a/lib/lsg_web/views/layout_view.ex
+++ b/lib/lsg_web/views/layout_view.ex
@@ -1,20 +1,78 @@
defmodule LSGWeb.LayoutView do
use LSGWeb, :view
-
+
+ def liquid_markdown(conn, text) do
+ context_path = cond do
+ conn.assigns[:chan] -> "/#{conn.assigns[:network]}/#{LSGWeb.format_chan(conn.assigns[:chan])}"
+ conn.assigns[:network] -> "/#{conn.assigns[:network]}/-"
+ true -> "/-"
+ end
+
+ {:ok, ast} = Liquex.parse(text)
+ context = Liquex.Context.new(%{
+ "context_path" => context_path
+ })
+ {content, _} = Liquex.render(ast, context)
+ content
+ |> to_string()
+ |> Earmark.as_html!()
+ |> raw()
+ end
+
+ def page_title(conn) do
+ target = cond do
+ conn.assigns[:chan] ->
+ "#{conn.assigns.chan} @ #{conn.assigns.network}"
+ conn.assigns[:network] -> conn.assigns.network
+ true -> Keyword.get(Application.get_env(:lsg, :irc), :name, "ircbot")
+ end
+
+ breadcrumb_title = Enum.map(Map.get(conn.assigns, :breadcrumbs)||[], fn({title, _href}) -> title end)
+
+ title = [conn.assigns[:title], breadcrumb_title, target]
+ |> List.flatten()
+ |> Enum.uniq()
+ |> Enum.filter(fn(x) -> x end)
+ |> Enum.intersperse(" / ")
+ |> Enum.join()
+
+ content_tag(:title, title)
+ end
+
def format_time(date, with_relative \\ true) do
alias Timex.Format.DateTime.Formatters
alias Timex.Timezone
date = if is_integer(date) do
date
|> DateTime.from_unix!(:millisecond)
- |> Timezone.convert("Europe/Paris")
+ |> DateTime.shift_zone!("Europe/Paris", Tzdata.TimeZoneDatabase)
else
date
+ |> DateTime.shift_zone!("Europe/Paris", Tzdata.TimeZoneDatabase)
+ end
+
+ now = DateTime.now!("Europe/Paris", Tzdata.TimeZoneDatabase)
+
+ now_week = Timex.iso_week(now)
+ date_week = Timex.iso_week(date)
+
+ {y, w} = now_week
+ now_last_week = {y, w-1}
+ now_last_roll = 7-Timex.days_to_beginning_of_week(now)
+
+ format = cond do
+ date.year != now.year -> "{D}/{M}/{YYYY} {h24}:{m}"
+ date.day == now.day -> "{h24}:{m}"
+ (now_week == date_week) || (date_week == now_last_week && (Date.day_of_week(date) >= now_last_roll)) -> "{WDfull} {h24}:{m}"
+ (now.month == date.month) -> "{WDfull} {D} {h24}:{m}"
+ true -> "{WDfull} {D} {M} {h24}:{m}"
end
+
{:ok, relative} = Formatters.Relative.relative_to(date, Timex.now("Europe/Paris"), "{relative}", "fr")
- {:ok, detail} = Formatters.Default.lformat(date, "{D}/{M}/{YYYY} {h24}:{m}", "fr")
+ {:ok, full} = Formatters.Default.lformat(date, "{WDfull} {D} {YYYY} {h24}:{m}", "fr") #"{h24}:{m} {WDfull} {D}", "fr")
+ {:ok, detail} = Formatters.Default.lformat(date, format, "fr") #"{h24}:{m} {WDfull} {D}", "fr")
- content_tag(:time, if(with_relative, do: relative, else: detail), [title: detail])
+ content_tag(:time, if(with_relative, do: relative, else: detail), [title: full])
end
end
diff --git a/lib/lsg_web/views/network_view.ex b/lib/lsg_web/views/network_view.ex
new file mode 100644
index 0000000..c369ce6
--- /dev/null
+++ b/lib/lsg_web/views/network_view.ex
@@ -0,0 +1,4 @@
+defmodule LSGWeb.NetworkView do
+ use LSGWeb, :view
+
+end