summaryrefslogtreecommitdiff
path: root/lib/nola/user_track.ex
diff options
context:
space:
mode:
Diffstat (limited to 'lib/nola/user_track.ex')
-rw-r--r--lib/nola/user_track.ex323
1 files changed, 230 insertions, 93 deletions
diff --git a/lib/nola/user_track.ex b/lib/nola/user_track.ex
index c1218b0..0b07a91 100644
--- a/lib/nola/user_track.ex
+++ b/lib/nola/user_track.ex
@@ -8,23 +8,23 @@ defmodule Nola.UserTrack do
# Privilege map:
# %{"#channel" => [:operator, :voice]
defmodule Storage do
-
def delete(id) do
- op(fn(ets) -> :ets.delete(ets, id) end)
+ op(fn ets -> :ets.delete(ets, id) end)
end
def insert(tuple) do
- op(fn(ets) -> :ets.insert(ets, tuple) end)
+ op(fn ets -> :ets.insert(ets, tuple) end)
end
def clear_network(network) do
- op(fn(ets) ->
+ op(fn ets ->
spec = [
{{:_, :"$1", :_, :_, :_, :_, :_, :_, :_, :_, :_, :_},
- [
- {:==, :"$1", {:const, network}}
- ], [:"$_"]}
+ [
+ {:==, :"$1", {:const, network}}
+ ], [:"$_"]}
]
+
:ets.match_delete(ets, spec)
end)
end
@@ -34,7 +34,7 @@ defmodule Nola.UserTrack do
end
def start_link do
- GenServer.start_link(__MODULE__, [], [name: __MODULE__])
+ GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
def init([]) do
@@ -43,13 +43,15 @@ defmodule Nola.UserTrack do
end
def handle_call({:op, fun}, _from, ets) do
- returned = try do
- {:ok, fun.(ets)}
- rescue
- rescued -> {:error, rescued}
- catch
- rescued -> {:error, rescued}
- end
+ returned =
+ try do
+ {:ok, fun.(ets)}
+ rescue
+ rescued -> {:error, rescued}
+ catch
+ rescued -> {:error, rescued}
+ end
+
{:reply, returned, ets}
end
@@ -58,31 +60,63 @@ defmodule Nola.UserTrack do
end
end
- defmodule Id, do: use EntropyString
+ defmodule Id, do: use(EntropyString)
defmodule User do
- defstruct [:id, :account, :network, :nick, {:nicks, []}, :username, :host, :realname, {:privileges, %{}}, {:last_active, %{}}, {:options, %{}}]
+ defstruct [
+ :id,
+ :account,
+ :network,
+ :nick,
+ {:nicks, []},
+ :username,
+ :host,
+ :realname,
+ {:privileges, %{}},
+ {:last_active, %{}},
+ {:options, %{}}
+ ]
def to_tuple(u = %__MODULE__{}) do
- {u.id || Nola.UserTrack.Id.large_id, u.network, u.account, String.downcase(u.nick), u.nick, u.nicks || [], u.username, u.host, u.realname, u.privileges, u.last_active, u.options}
+ {u.id || Nola.UserTrack.Id.large_id(), u.network, u.account, String.downcase(u.nick),
+ u.nick, u.nicks || [], u.username, u.host, u.realname, u.privileges, u.last_active,
+ u.options}
end
- #tuple size: 11
- def from_tuple({id, network, account, _downcased_nick, nick, nicks, username, host, realname, privs, last_active, opts}) do
- struct = %__MODULE__{id: id, account: account, network: network, nick: nick, nicks: nicks, username: username, host: host, realname: realname, privileges: privs, last_active: last_active, options: opts}
+ # tuple size: 11
+ def from_tuple(
+ {id, network, account, _downcased_nick, nick, nicks, username, host, realname, privs,
+ last_active, opts}
+ ) do
+ struct = %__MODULE__{
+ id: id,
+ account: account,
+ network: network,
+ nick: nick,
+ nicks: nicks,
+ username: username,
+ host: host,
+ realname: realname,
+ privileges: privs,
+ last_active: last_active,
+ options: opts
+ }
end
end
def find_by_account(%Nola.Account{id: id}) do
- #iex(15)> :ets.fun2ms(fn(obj = {_, net, acct, _, _, _, _, _, _}) when net == network and acct == account -> obj end)
+ # iex(15)> :ets.fun2ms(fn(obj = {_, net, acct, _, _, _, _, _, _}) when net == network and acct == account -> obj end)
spec = [
{{:_, :_, :"$2", :_, :_, :_, :_, :_, :_, :_, :_, :_},
[
- {:==, :"$2", {:const, id}}
+ {:==, :"$2", {:const, id}}
], [:"$_"]}
]
- results = :ets.select(@ets, spec)
- |> Enum.filter(& &1)
+
+ results =
+ :ets.select(@ets, spec)
+ |> Enum.filter(& &1)
+
for obj <- results, do: User.from_tuple(obj)
end
@@ -91,27 +125,39 @@ defmodule Nola.UserTrack do
end
def find_by_account(network, %Nola.Account{id: id}) do
- #iex(15)> :ets.fun2ms(fn(obj = {_, net, acct, _, _, _, _, _, _}) when net == network and acct == account -> obj end)
+ # iex(15)> :ets.fun2ms(fn(obj = {_, net, acct, _, _, _, _, _, _}) when net == network and acct == account -> obj end)
spec = [
{{:_, :"$1", :"$2", :_, :_, :_, :_, :_, :_, :_, :_, :_},
[
- {:andalso, {:==, :"$1", {:const, network}},
- {:==, :"$2", {:const, id}}}
+ {:andalso, {:==, :"$1", {:const, network}}, {:==, :"$2", {:const, id}}}
], [:"$_"]}
]
+
case :ets.select(@ets, spec) do
results = [_r | _] ->
- result = results
- |> Enum.reject(fn({_, net, _, _, _, _, _, _, _, _, actives, opts}) -> network != "matrix" && net == "matrix" end)
- |> Enum.reject(fn({_, net, _, _, _, _, _, _, _, _, actives, opts}) -> network != "telegram" && net == "telegram" end)
- |> Enum.reject(fn({_, _, _, _, _, _, _, _, _, _, actives, opts}) -> network not in ["matrix", "telegram"] && Map.get(opts, :puppet) end)
- |> Enum.sort_by(fn({_, _, _, _, _, _, _, _, _, _, actives, _}) ->
- Map.get(actives, nil)
- end, {:desc, NaiveDateTime})
- |> List.first
+ result =
+ results
+ |> Enum.reject(fn {_, net, _, _, _, _, _, _, _, _, actives, opts} ->
+ network != "matrix" && net == "matrix"
+ end)
+ |> Enum.reject(fn {_, net, _, _, _, _, _, _, _, _, actives, opts} ->
+ network != "telegram" && net == "telegram"
+ end)
+ |> Enum.reject(fn {_, _, _, _, _, _, _, _, _, _, actives, opts} ->
+ network not in ["matrix", "telegram"] && Map.get(opts, :puppet)
+ end)
+ |> Enum.sort_by(
+ fn {_, _, _, _, _, _, _, _, _, _, actives, _} ->
+ Map.get(actives, nil)
+ end,
+ {:desc, NaiveDateTime}
+ )
+ |> List.first()
if result, do: User.from_tuple(result)
- _ -> nil
+
+ _ ->
+ nil
end
end
@@ -119,18 +165,23 @@ defmodule Nola.UserTrack do
Storage.clear_network(network)
end
-
def merge_account(old_id, new_id) do
- #iex(15)> :ets.fun2ms(fn(obj = {_, net, acct, _, _, _, _, _, _}) when net == network and acct == account -> obj end)
+ # iex(15)> :ets.fun2ms(fn(obj = {_, net, acct, _, _, _, _, _, _}) when net == network and acct == account -> obj end)
spec = [
{{:_, :_, :"$1", :_, :_, :_, :_, :_, :_, :_, :_, :_},
[
- {:==, :"$1", {:const, old_id}}
+ {:==, :"$1", {:const, old_id}}
], [:"$_"]}
]
- Enum.each(:ets.select(@ets, spec), fn({id, net, _, downcased_nick, nick, nicks, username, host, realname, privs, active, opts}) ->
- Storage.op(fn(ets) ->
- :ets.insert(@ets, {id, net, new_id, downcased_nick, nick, nicks, username, host, realname, privs, active, opts})
+
+ Enum.each(:ets.select(@ets, spec), fn {id, net, _, downcased_nick, nick, nicks, username,
+ host, realname, privs, active, opts} ->
+ Storage.op(fn ets ->
+ :ets.insert(
+ @ets,
+ {id, net, new_id, downcased_nick, nick, nicks, username, host, realname, privs, active,
+ opts}
+ )
end)
end)
end
@@ -139,14 +190,18 @@ defmodule Nola.UserTrack do
find_by_nick(network, nick)
end
-
def find_by_nick(%ExIRC.SenderInfo{network: network, nick: nick}) do
find_by_nick(network, nick)
end
def find_by_nick(network, nick) do
- case :ets.match(@ets, {:"$1", network, :_, String.downcase(nick), :_, :_, :_, :_, :_, :_, :_, :_}) do
- [[id] | _] -> lookup(id)
+ case :ets.match(
+ @ets,
+ {:"$1", network, :_, String.downcase(nick), :_, :_, :_, :_, :_, :_, :_, :_}
+ ) do
+ [[id] | _] ->
+ lookup(id)
+
_ ->
nil
end
@@ -171,7 +226,7 @@ defmodule Nola.UserTrack do
end
def channel(network, channel) do
- Enum.filter(to_list(), fn({_, network, _, _, _, _, _, _, _, channels, _, _}) ->
+ Enum.filter(to_list(), fn {_, network, _, _, _, _, _, _, _, channels, _, _} ->
Map.get(channels, channel)
end)
end
@@ -179,53 +234,92 @@ defmodule Nola.UserTrack do
# TODO
def connected(network, nick, user, host, account_id, opts \\ %{}) do
if account = Nola.Account.get(account_id) do
- user = if user = find_by_nick(network, nick) do
- user
- else
- user = %User{id: Nola.UserTrack.Id.large_id, account: account_id, network: network, nick: nick, username: user, host: host, privileges: %{}, options: opts}
- Storage.op(fn(ets) ->
- :ets.insert(ets, User.to_tuple(user))
- end)
- user
- end
+ user =
+ if user = find_by_nick(network, nick) do
+ user
+ else
+ user = %User{
+ id: Nola.UserTrack.Id.large_id(),
+ account: account_id,
+ network: network,
+ nick: nick,
+ username: user,
+ host: host,
+ privileges: %{},
+ options: opts
+ }
+
+ Storage.op(fn ets ->
+ :ets.insert(ets, User.to_tuple(user))
+ end)
+
+ user
+ end
+
+ Nola.Irc.Connection.publish_event(network, %{
+ type: :connect,
+ user_id: user.id,
+ account_id: user.account
+ })
- Nola.Irc.Connection.publish_event(network, %{type: :connect, user_id: user.id, account_id: user.account})
:ok
else
:error
end
end
- def joined(c, s), do: joined(c,s,[])
+ def joined(c, s), do: joined(c, s, [])
- def joined(channel, sender=%{nick: nick, user: uname, host: host}, privileges, touch \\ true) do
- privileges = if Nola.Irc.admin?(sender) do
- privileges ++ [:admin]
- else privileges end
- user = if user = find_by_nick(sender.network, nick) do
- %User{user | username: uname, host: host, privileges: Map.put(user.privileges || %{}, channel, privileges)}
- else
- user = %User{id: Nola.UserTrack.Id.large_id, network: sender.network, nick: nick, username: uname, host: host, privileges: %{channel => privileges}}
+ def joined(channel, sender = %{nick: nick, user: uname, host: host}, privileges, touch \\ true) do
+ privileges =
+ if Nola.Irc.admin?(sender) do
+ privileges ++ [:admin]
+ else
+ privileges
+ end
+
+ user =
+ if user = find_by_nick(sender.network, nick) do
+ %User{
+ user
+ | username: uname,
+ host: host,
+ privileges: Map.put(user.privileges || %{}, channel, privileges)
+ }
+ else
+ user = %User{
+ id: Nola.UserTrack.Id.large_id(),
+ network: sender.network,
+ nick: nick,
+ username: uname,
+ host: host,
+ privileges: %{channel => privileges}
+ }
+
+ account = Nola.Account.lookup(user).id
+ user = %User{user | account: account}
+ end
- account = Nola.Account.lookup(user).id
- user = %User{user | account: account}
- end
user = touch_struct(user, channel)
if touch && user.account do
Nola.Membership.touch(user.account, sender.network, channel)
end
- Storage.op(fn(ets) ->
+ Storage.op(fn ets ->
:ets.insert(ets, User.to_tuple(user))
end)
- Nola.Irc.Connection.publish_event({sender.network, channel}, %{type: :join, user_id: user.id, account_id: user.account})
+ Nola.Irc.Connection.publish_event({sender.network, channel}, %{
+ type: :join,
+ user_id: user.id,
+ account_id: user.account
+ })
user
end
- #def joined(network, channel, nick, privileges) do
+ # def joined(network, channel, nick, privileges) do
# user = if user = find_by_nick(network, nick) do
# %User{user | privileges: Map.put(user.privileges, channel, privileges)}
# else
@@ -235,18 +329,24 @@ defmodule Nola.UserTrack do
# Storage.op(fn(ets) ->
# :ets.insert(ets, User.to_tuple(user))
# end)
- #end
+ # end
+
+ def messaged(
+ %Nola.Message{network: network, account: account, channel: chan, sender: %{nick: nick}} =
+ m
+ ) do
+ {user, account} =
+ if user = find_by_nick(network, nick) do
+ {touch_struct(user, chan), account || Nola.Account.lookup(user)}
+ else
+ user = %User{network: network, nick: nick, privileges: %{}}
+ account = Nola.Account.lookup(user)
+ {%User{user | account: account.id}, account}
+ end
- def messaged(%Nola.Message{network: network, account: account, channel: chan, sender: %{nick: nick}} = m) do
- {user, account} = if user = find_by_nick(network, nick) do
- {touch_struct(user, chan), account || Nola.Account.lookup(user)}
- else
- user = %User{network: network, nick: nick, privileges: %{}}
- account = Nola.Account.lookup(user)
- {%User{user | account: account.id}, account}
- end
Storage.insert(User.to_tuple(user))
if chan, do: Nola.Membership.touch(account, network, chan)
+
if !m.account do
{:ok, %Nola.Message{m | account: account}}
else
@@ -257,12 +357,19 @@ defmodule Nola.UserTrack do
def renamed(network, old_nick, new_nick) do
if user = find_by_nick(network, old_nick) do
old_account = Nola.Account.lookup(user)
- user = %User{user | nick: new_nick, nicks: [old_nick|user.nicks]}
+ user = %User{user | nick: new_nick, nicks: [old_nick | user.nicks]}
account = Nola.Account.lookup(user, false) || old_account
- user = %User{user | nick: new_nick, account: account.id, nicks: [old_nick|user.nicks]}
+ user = %User{user | nick: new_nick, account: account.id, nicks: [old_nick | user.nicks]}
Storage.insert(User.to_tuple(user))
channels = for {channel, _} <- user.privileges, do: channel
- Nola.Irc.Connection.publish_event(network, %{type: :nick, user_id: user.id, account_id: account.id, nick: new_nick, old_nick: old_nick})
+
+ Nola.Irc.Connection.publish_event(network, %{
+ type: :nick,
+ user_id: user.id,
+ account_id: account.id,
+ nick: new_nick,
+ old_nick: old_nick
+ })
end
end
@@ -270,12 +377,19 @@ defmodule Nola.UserTrack do
if user = find_by_nick(network, nick) do
privs = Map.get(user.privileges, channel)
- privs = Enum.reduce(add, privs, fn(priv, acc) -> [priv|acc] end)
- privs = Enum.reduce(remove, privs, fn(priv, acc) -> List.delete(acc, priv) end)
+ privs = Enum.reduce(add, privs, fn priv, acc -> [priv | acc] end)
+ privs = Enum.reduce(remove, privs, fn priv, acc -> List.delete(acc, priv) end)
user = %User{user | privileges: Map.put(user.privileges, channel, privs)}
Storage.insert(User.to_tuple(user))
- Nola.Irc.Connection.publish_event({network, channel}, %{type: :privileges, user_id: user.id, account_id: user.account, added: add, removed: remove})
+
+ Nola.Irc.Connection.publish_event({network, channel}, %{
+ type: :privileges,
+ user_id: user.id,
+ account_id: user.account,
+ added: add,
+ removed: remove
+ })
end
end
@@ -292,12 +406,25 @@ defmodule Nola.UserTrack do
privs = Map.delete(user.privileges, channel)
lasts = Map.delete(user.last_active, channel)
+
if Enum.count(privs) > 0 do
user = %User{user | privileges: privs}
Storage.insert(User.to_tuple(user))
- Nola.Irc.Connection.publish_event({network, channel}, %{type: :part, user_id: user.id, account_id: user.account, reason: nil})
+
+ Nola.Irc.Connection.publish_event({network, channel}, %{
+ type: :part,
+ user_id: user.id,
+ account_id: user.account,
+ reason: nil
+ })
else
- Nola.Irc.Connection.publish_event(network, %{type: :quit, user_id: user.id, account_id: user.account, reason: "Left all known channels"})
+ Nola.Irc.Connection.publish_event(network, %{
+ type: :quit,
+ user_id: user.id,
+ account_id: user.account,
+ reason: "Left all known channels"
+ })
+
Storage.delete(user.id)
end
end
@@ -309,17 +436,27 @@ defmodule Nola.UserTrack do
for {channel, _} <- user.privileges do
Nola.Membership.touch(user.account, sender.network, channel)
end
- Nola.Irc.Connection.publish_event(sender.network, %{type: :quit, user_id: user.id, account_id: user.account, reason: reason})
+
+ Nola.Irc.Connection.publish_event(sender.network, %{
+ type: :quit,
+ user_id: user.id,
+ account_id: user.account,
+ reason: reason
+ })
end
+
Storage.delete(user.id)
end
end
defp touch_struct(user = %User{last_active: last_active}, channel) do
now = NaiveDateTime.utc_now()
- last_active = last_active
- |> Map.put(channel, now)
- |> Map.put(nil, now)
+
+ last_active =
+ last_active
+ |> Map.put(channel, now)
+ |> Map.put(nil, now)
+
%User{user | last_active: last_active}
end