summaryrefslogtreecommitdiff
path: root/lib/nola_telegram
diff options
context:
space:
mode:
Diffstat (limited to 'lib/nola_telegram')
-rw-r--r--lib/nola_telegram/room.ex188
-rw-r--r--lib/nola_telegram/telegram.ex233
2 files changed, 0 insertions, 421 deletions
diff --git a/lib/nola_telegram/room.ex b/lib/nola_telegram/room.ex
deleted file mode 100644
index ca8a437..0000000
--- a/lib/nola_telegram/room.ex
+++ /dev/null
@@ -1,188 +0,0 @@
-defmodule Nola.TelegramRoom do
- require Logger
- @behaviour Telegram.ChatBot
- alias Telegram.Api
-
- @couch "bot-telegram-rooms"
-
- def rooms(), do: rooms(:with_docs)
-
- @spec rooms(:with_docs | :ids) :: [Map.t | integer( )]
- def rooms(:with_docs) do
- case Couch.get(@couch, :all_docs, include_docs: true) do
- {:ok, %{"rows" => rows}} -> {:ok, for(%{"doc" => doc} <- rows, do: doc)}
- error = {:error, _} -> error
- end
- end
-
- def rooms(:ids) do
- case Couch.get(@couch, :all_docs) do
- {:ok, %{"rows" => rows}} -> {:ok, for(%{"id" => id} <- rows, do: id)}
- error = {:error, _} -> error
- end
- end
-
- def room(id, opts \\ []) do
- Couch.get(@couch, id, opts)
- end
-
- # TODO: Create couch
- def setup() do
- :ok
- end
-
- def after_start() do
- for id <- room(:ids), do: Telegram.Bot.ChatBot.Chat.Session.Supervisor.start_child(Nola.Telegram, Integer.parse(id) |> elem(0))
- end
-
- @impl Telegram.ChatBot
- def init(id) when is_integer(id) and id < 0 do
- token = Keyword.get(Application.get_env(:nola, :telegram, []), :key)
- {:ok, chat} = Api.request(token, "getChat", chat_id: id)
- Logger.metadata(transport: :telegram, id: id, telegram_room_id: id)
- tg_room = case room(id) do
- {:ok, tg_room = %{"network" => _net, "channel" => _chan}} -> tg_room
- {:error, :not_found} ->
- [net, chan] = String.split(chat["title"], "/", parts: 2)
- {net, chan} = case IRC.Connection.get_network(net, chan) do
- %IRC.Connection{} -> {net, chan}
- _ -> {nil, nil}
- end
- {:ok, _id, _rev} = Couch.post(@couch, %{"_id" => id, "network" => net, "channel" => nil})
- {:ok, tg_room} = room(id)
- tg_room
- end
- %{"network" => net, "channel" => chan} = tg_room
- Logger.info("Starting ChatBot for room #{id} \"#{chat["title"]}\" #{inspect tg_room}")
- irc_plumbed = if net && chan do
- {:ok, _} = Registry.register(IRC.PubSub, "#{net}/#{chan}:messages", plugin: __MODULE__)
- {:ok, _} = Registry.register(IRC.PubSub, "#{net}/#{chan}:triggers", plugin: __MODULE__)
- {:ok, _} = Registry.register(IRC.PubSub, "#{net}/#{chan}:outputs", plugin: __MODULE__)
- true
- else
- Logger.warn("Did not found telegram match for #{id} \"#{chat["title"]}\"")
- false
- end
- {:ok, %{id: id, net: net, chan: chan, irc: irc_plumbed}}
- end
-
- def init(id) do
- Logger.error("telegram_room: bad id (not room id)", transport: :telegram, id: id, telegram_room_id: id)
- :ignoree
- end
-
- defp find_or_create_meta_account(from = %{"id" => user_id}, state) do
- if account = IRC.Account.find_meta_account("telegram-id", user_id) do
- account
- else
- first_name = Map.get(from, "first_name")
- last_name = Map.get(from, "last_name")
- name = [first_name, last_name]
- |> Enum.filter(& &1)
- |> Enum.join(" ")
-
- username = Map.get(from, "username", first_name)
-
- account = username
- |> IRC.Account.new_account()
- |> IRC.Account.update_account_name(name)
- |> IRC.Account.put_meta("telegram-id", user_id)
-
- Logger.info("telegram_room: created account #{account.id} for telegram user #{user_id}")
- account
- end
- end
-
- def handle_update(%{"message" => %{"from" => from = %{"id" => user_id}, "text" => text}}, _token, state) do
- account = find_or_create_meta_account(from, state)
- connection = IRC.Connection.get_network(state.net)
- IRC.send_message_as(account, state.net, state.chan, text, true)
- {:ok, state}
- end
-
- def handle_update(data = %{"message" => %{"from" => from = %{"id" => user_id}, "location" => %{"latitude" => lat, "longitude" => lon}}}, _token, state) do
- account = find_or_create_meta_account(from, state)
- connection = IRC.Connection.get_network(state.net)
- IRC.send_message_as(account, state.net, state.chan, "@ #{lat}, #{lon}", true)
- {:ok, state}
- end
-
- for type <- ~w(photo voice video document animation) do
- def handle_update(data = %{"message" => %{unquote(type) => _}}, token, state) do
- upload(unquote(type), data, token, state)
- end
- end
-
- def handle_update(update, token, state) do
- {:ok, state}
- end
-
- def handle_info({:irc, _, _, message}, state) do
- handle_info({:irc, nil, message}, state)
- end
-
- def handle_info({:irc, _, message = %IRC.Message{sender: %{nick: nick}, text: text}}, state) do
- if Map.get(message.meta, :from) == self() do
- else
- body = if Map.get(message.meta, :self), do: text, else: "<#{nick}> #{text}"
- Nola.Telegram.send_message(state.id, body)
- end
- {:ok, state}
- end
-
- def handle_info(info, state) do
- Logger.info("UNhandled #{inspect info}")
- {:ok, state}
- end
-
- defp upload(_type, %{"message" => m = %{"chat" => %{"id" => chat_id}, "from" => from = %{"id" => user_id}}}, token, state) do
- account = find_or_create_meta_account(from, state)
- if account do
- {content, type} = cond do
- m["photo"] -> {m["photo"], "photo"}
- m["voice"] -> {m["voice"], "voice message"}
- m["video"] -> {m["video"], "video"}
- m["document"] -> {m["document"], "file"}
- m["animation"] -> {m["animation"], "gif"}
- end
-
- file = if is_list(content) && Enum.count(content) > 1 do
- Enum.sort_by(content, fn(p) -> p["file_size"] end, &>=/2)
- |> List.first()
- else
- content
- end
-
- file_id = file["file_id"]
- file_unique_id = file["file_unique_id"]
- text = if(m["caption"], do: m["caption"] <> " ", else: "")
-
- spawn(fn() ->
- with \
- {:ok, file} <- Telegram.Api.request(token, "getFile", file_id: file_id),
- path = "https://api.telegram.org/file/bot#{token}/#{file["file_path"]}",
- {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- HTTPoison.get(path),
- <<smol_body::binary-size(20), _::binary>> = body,
- {:ok, magic} <- GenMagic.Pool.perform(Nola.GenMagic, {:bytes, smol_body}),
- bucket = Application.get_env(:nola, :s3, []) |> Keyword.get(:bucket),
- ext = Path.extname(file["file_path"]),
- s3path = "#{account.id}/#{file_unique_id}#{ext}",
- s3req = ExAws.S3.put_object(bucket, s3path, body, acl: :public_read, content_type: magic.mime_type),
- {:ok, _} <- ExAws.request(s3req)
- do
- path = NolaWeb.Router.Helpers.url(NolaWeb.Endpoint) <> "/files/#{s3path}"
- txt = "#{type}: #{text}#{path}"
- connection = IRC.Connection.get_network(state.net)
- IRC.send_message_as(account, state.net, state.chan, txt, true)
- else
- error ->
- Telegram.Api.request(token, "sendMessage", chat_id: chat_id, text: "File upload failed, sorry.")
- Logger.error("Failed upload from Telegram: #{inspect error}")
- end
- end)
-
- {:ok, state}
- end
- end
-
-end
diff --git a/lib/nola_telegram/telegram.ex b/lib/nola_telegram/telegram.ex
deleted file mode 100644
index 1c6a9a9..0000000
--- a/lib/nola_telegram/telegram.ex
+++ /dev/null
@@ -1,233 +0,0 @@
-defmodule Nola.Telegram do
- require Logger
- @behaviour Telegram.ChatBot
-
- def my_path() do
- "https://t.me/beauttebot"
- end
-
- def send_message(id, text, md2 \\ false) do
- md = if md2, do: "MarkdownV2", else: "Markdown"
- token = Keyword.get(Application.get_env(:nola, :telegram, []), :key)
- Telegram.Bot.ChatBot.Chat.Session.Supervisor.start_child(Nola.Telegram, id)
- Telegram.Api.request(token, "sendMessage", chat_id: id, text: text, parse_mode: "Markdown")
- end
-
- @impl Telegram.ChatBot
- def init(chat_id) when chat_id < 0 do
- {:ok, state} = Nola.TelegramRoom.init(chat_id)
- {:ok, %{room_state: state}}
- end
- def init(chat_id) do
- Logger.info("Telegram session starting: #{chat_id}")
- account = IRC.Account.find_meta_account("telegram-id", chat_id)
- account_id = if account, do: account.id
- {:ok, %{account: account_id}}
- end
-
- @impl Telegram.ChatBot
- def handle_update(update, token, %{room_state: room_state}) do
- {:ok, room_state} = Nola.TelegramRoom.handle_update(update, token, room_state)
- {:ok, %{room_state: room_state}}
- end
-
- def handle_update(%{"message" => m = %{"chat" => %{"type" => "private"}, "text" => text = "/start"<>_}}, _token, state) do
- text = "*Welcome to beautte!*\n\nQuery the bot on IRC and say \"enable-telegram\" to continue."
- send_message(m["chat"]["id"], text)
- {:ok, %{account: nil}}
- end
-
- def handle_update(%{"message" => m = %{"chat" => %{"type" => "private"}, "text" => text = "/enable"<>_}}, _token, state) do
- key = case String.split(text, " ") do
- ["/enable", key | _] -> key
- _ -> "nil"
- end
-
- #Handled message "1247435154:AAGnSSCnySn0RuVxy_SUcDEoOX_rbF6vdq0" %{"message" =>
- # %{"chat" => %{"first_name" => "J", "id" => 2075406, "type" => "private", "username" => "ahref"},
- # "date" => 1591027272, "entities" =>
- # [%{"length" => 7, "offset" => 0, "type" => "bot_command"}],
- # "from" => %{"first_name" => "J", "id" => 2075406, "is_bot" => false, "language_code" => "en", "username" => "ahref"},
- # "message_id" => 11, "text" => "/enable salope"}, "update_id" => 764148578}
- account = IRC.Account.find_meta_account("telegram-validation-code", String.downcase(key))
- text = if account do
- net = IRC.Account.get_meta(account, "telegram-validation-target")
- IRC.Account.put_meta(account, "telegram-id", m["chat"]["id"])
- IRC.Account.put_meta(account, "telegram-username", m["chat"]["username"])
- IRC.Account.put_meta(account, "telegram-username", m["chat"]["username"])
- IRC.Account.delete_meta(account, "telegram-validation-code")
- IRC.Account.delete_meta(account, "telegram-validation-target")
- IRC.Connection.broadcast_message(net, account, "Telegram #{m["chat"]["username"]} account added!")
- "Yay! Linked to account **#{account.name}**."
- else
- "Token invalid"
- end
- send_message(m["chat"]["id"], text)
- {:ok, %{account: account.id}}
- end
-
- #[debug] Unhandled update: %{"message" =>
- # %{"chat" => %{"first_name" => "J", "id" => 2075406, "type" => "private", "username" => "ahref"},
- # "date" => 1591096015,
- # "from" => %{"first_name" => "J", "id" => 2075406, "is_bot" => false, "language_code" => "en", "username" => "ahref"},
- # "message_id" => 29,
- # "photo" => [
- # %{"file_id" => "AgACAgQAAxkBAAMdXtYyz4RQqLcpOlR6xKK3w3NayHAAAnCzMRuL4bFSgl_cTXMl4m5G_T0kXQADAQADAgADbQADZVMBAAEaBA",
- # "file_size" => 9544, "file_unique_id" => "AQADRv09JF0AA2VTAQAB", "height" => 95, "width" => 320},
- # %{"file_id" => "AgACAgQAAxkBAAMdXtYyz4RQqLcpOlR6xKK3w3NayHAAAnCzMRuL4bFSgl_cTXMl4m5G_T0kXQADAQADAgADeAADZFMBAAEaBA",
- # "file_size" => 21420, "file_unique_id" => "AQADRv09JF0AA2RTAQAB", "height" => 148, "width" => 501}]},
- # "update_id" => 218161546}
-
- for type <- ~w(photo voice video document animation) do
- def handle_update(data = %{"message" => %{unquote(type) => _}}, token, state) do
- start_upload(unquote(type), data, token, state)
- end
- end
-
- #[debug] Unhandled update: %{"callback_query" =>
- # %{
- # "chat_instance" => "-7948978714441865930", "data" => "evolu.net/#dmz",
- # "from" => %{"first_name" => "J", "id" => 2075406, "is_bot" => false, "language_code" => "en", "username" => "ahref"},
- # "id" => "8913804780149600",
- # "message" => %{"chat" => %{"first_name" => "J", "id" => 2075406, "type" => "private", "username" => "ahref"},
- # "date" => 1591098553, "from" => %{"first_name" => "devbeautte", "id" => 1293058838, "is_bot" => true, "username" => "devbeauttebot"},
- # "message_id" => 62,
- # "reply_markup" => %{"inline_keyboard" => [[%{"callback_data" => "random/#", "text" => "random/#"},
- # %{"callback_data" => "evolu.net/#dmz", "text" => "evolu.net/#dmz"}]]},
- # "text" => "Where should I send the file?"}
- # }
- # , "update_id" => 218161568}
-
- #def handle_update(t, %{"callback_query" => cb = %{"data" => "resend", "id" => id, "message" => m = %{"message_id" => m_id, "chat" => %{"id" => chat_id}, "reply_to_message" => op}}}) do
- #end
-
- def handle_update(%{"callback_query" => cb = %{"data" => "start-upload:"<>target, "id" => id, "message" => m = %{"message_id" => m_id, "chat" => %{"id" => chat_id}, "reply_to_message" => op}}}, t, state) do
- account = IRC.Account.find_meta_account("telegram-id", chat_id)
- if account do
- target = case String.split(target, "/") do
- ["everywhere"] -> IRC.Membership.of_account(account)
- [net, chan] -> [{net, chan}]
- end
- Telegram.Api.request(t, "editMessageText", chat_id: chat_id, message_id: m_id, text: "Processing...", reply_markup: %{})
-
- {content, type} = cond do
- op["photo"] -> {op["photo"], ""}
- op["voice"] -> {op["voice"], " a voice message"}
- op["video"] -> {op["video"], ""}
- op["document"] -> {op["document"], ""}
- op["animation"] -> {op["animation"], ""}
- end
-
- file = if is_list(content) && Enum.count(content) > 1 do
- Enum.sort_by(content, fn(p) -> p["file_size"] end, &>=/2)
- |> List.first()
- else
- content
- end
- file_id = file["file_id"]
- file_unique_id = file["file_unique_id"]
- text = if(op["caption"], do: ": "<> op["caption"] <> "", else: "")
- resend = %{"inline_keyboard" => [ [%{"text" => "re-share", "callback_data" => "resend"}] ]}
- spawn(fn() ->
- with \
- {:ok, file} <- Telegram.Api.request(t, "getFile", file_id: file_id),
- path = "https://api.telegram.org/file/bot#{t}/#{file["file_path"]}",
- {:ok, %HTTPoison.Response{status_code: 200, body: body}} <- HTTPoison.get(path),
- <<smol_body::binary-size(20), _::binary>> = body,
- {:ok, magic} <- GenMagic.Pool.perform(Nola.GenMagic, {:bytes, smol_body}),
- bucket = Application.get_env(:nola, :s3, []) |> Keyword.get(:bucket),
- ext = Path.extname(file["file_path"]),
- s3path = "#{account.id}/#{file_unique_id}#{ext}",
- Telegram.Api.request(t, "editMessageText", chat_id: chat_id, message_id: m_id, text: "*Uploading...*", reply_markup: %{}, parse_mode: "MarkdownV2"),
- s3req = ExAws.S3.put_object(bucket, s3path, body, acl: :public_read, content_type: magic.mime_type),
- {:ok, _} <- ExAws.request(s3req)
- do
- path = NolaWeb.Router.Helpers.url(NolaWeb.Endpoint) <> "/files/#{s3path}"
- sent = for {net, chan} <- target do
- txt = "sent#{type}#{text} #{path}"
- IRC.send_message_as(account, net, chan, txt)
- "#{net}/#{chan}"
- end
- if caption = op["caption"], do: as_irc_message(chat_id, caption, account)
- text = "Sent on " <> Enum.join(sent, ", ") <> " !"
- Telegram.Api.request(t, "editMessageText", chat_id: chat_id, message_id: m_id, text: "_Sent!_", reply_markup: %{}, parse_mode: "MarkdownV2")
- else
- error ->
- Telegram.Api.request(t, "editMessageText", chat_id: chat_id, message_id: m_id, text: "Something failed.", reply_markup: %{}, parse_mode: "MarkdownV2")
- Logger.error("Failed upload from Telegram: #{inspect error}")
- end
- end)
- end
- {:ok, state}
- end
-
- def handle_update(%{"message" => m = %{"chat" => %{"id" => id, "type" => "private"}, "text" => text}}, _, state) do
- account = IRC.Account.find_meta_account("telegram-id", id)
- if account do
- as_irc_message(id, text, account)
- end
- {:ok, state}
- end
-
- def handle_update(m, _, state) do
- Logger.debug("Unhandled update: #{inspect m}")
- {:ok, state}
- end
-
- @impl Telegram.ChatBot
- def handle_info(info, %{room_state: room_state}) do
- {:ok, room_state} = Nola.TelegramRoom.handle_info(info, room_state)
- {:ok, %{room_state: room_state}}
- end
-
- def handle_info(_info, state) do
- {:ok, state}
- end
-
- defp as_irc_message(id, text, account) do
- reply_fun = fn(text) -> send_message(id, text) end
- trigger_text = cond do
- String.starts_with?(text, "/") ->
- "/"<>text = text
- "!"<>text
- Enum.any?(IRC.Connection.triggers(), fn({trigger, _}) -> String.starts_with?(text, trigger) end) ->
- text
- true ->
- "!"<>text
- end
- message = %IRC.Message{
- id: FlakeId.get(),
- transport: :telegram,
- network: "telegram",
- channel: nil,
- text: text,
- account: account,
- sender: %ExIRC.SenderInfo{nick: account.name},
- replyfun: reply_fun,
- trigger: IRC.Connection.extract_trigger(trigger_text),
- at: nil
- }
- IRC.Connection.publish(message, ["messages:private", "messages:telegram", "telegram/#{account.id}:messages"])
- message
- end
-
- defp start_upload(_type, %{"message" => m = %{"chat" => %{"id" => id, "type" => "private"}}}, token, state) do
- account = IRC.Account.find_meta_account("telegram-id", id)
- if account do
- text = if(m["text"], do: m["text"], else: nil)
- targets = IRC.Membership.of_account(account)
- |> Enum.map(fn({net, chan}) -> "#{net}/#{chan}" end)
- |> Enum.map(fn(i) -> %{"text" => i, "callback_data" => "start-upload:#{i}"} end)
- kb = if Enum.count(targets) > 1 do
- [%{"text" => "everywhere", "callback_data" => "start-upload:everywhere"}] ++ targets
- else
- targets
- end
- |> Enum.chunk_every(2)
- keyboard = %{"inline_keyboard" => kb}
- Telegram.Api.request(token, "sendMessage", chat_id: id, text: "Where should I send this file?", reply_markup: keyboard, reply_to_message_id: m["message_id"], parse_mode: "MarkdownV2")
- end
- {:ok, state}
- end
-
-end