Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
333a7cb
- Created Email.Protocol.Pop3 for pop3 protocol
d4rk5eed Jan 30, 2018
1978190
- added get_updates
Jan 31, 2018
533953d
wip
d4rk5eed Feb 1, 2018
4333247
email helpers
Feb 17, 2018
6a7af56
remove commented dependencies
Feb 19, 2018
8775159
Merge pull request #3 from Victoria91/email_helpers
d4rk5eed Feb 19, 2018
a64cff9
refactoring and test fix
Feb 19, 2018
a2e4a6b
fix helper module name
Feb 19, 2018
4a68718
Merge pull request #4 from Victoria91/fix-module-name
d4rk5eed Feb 20, 2018
549a077
fetch update interval from config
Feb 21, 2018
f3ca092
Merge pull request #5 from Victoria91/update_interval_to_config
d4rk5eed Feb 21, 2018
da842f3
Merge pull request #1 from agalaframework/add-pop3-mailer
Victoria91 Feb 22, 2018
dd511b2
delete messages and quit
Feb 22, 2018
d81549f
Merge pull request #6 from Victoria91/delete_and_quit
d4rk5eed Feb 22, 2018
f030468
add missing methods to pop3_mock
Feb 22, 2018
c7a1f96
Merge pull request #7 from Victoria91/delete_and_quit
d4rk5eed Feb 22, 2018
776a43d
Merge pull request #2 from agalaframework/add-pop3-mailer
Victoria91 Feb 26, 2018
f49c8af
Merge pull request #8 from Victoria91/add-pop3-mailer
d4rk5eed Feb 26, 2018
18344bf
add email headers for reply
Mar 5, 2018
93f8865
remove mail sending form agala_email
Mar 12, 2018
ee29ed7
Merge pull request #9 from Victoria91/add_email_reply
d4rk5eed Mar 13, 2018
82c19b7
Merge pull request #3 from agalaframework/add-pop3-mailer
Victoria91 Mar 14, 2018
578bbaa
provide loggging on get updates
Mar 14, 2018
4aec18b
Merge pull request #10 from Victoria91/logging_on_get_updates
d4rk5eed Mar 15, 2018
a2dcf0e
agala3 update
Jul 16, 2018
da46e40
Merge pull request #13 from Victoria91/agala3-update
Virviil Jul 18, 2018
6ae615c
Updateing agala version
Virviil Jul 18, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
elixir 1.6.0
10 changes: 8 additions & 2 deletions lib/agala_email.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@ defmodule Agala.Provider.Email do
@moduledoc """
Module providing email connection.
"""

use Agala.Provider

@pop3 Agala.Provider.Email.Protocol.Pop3
@pop3_mock Agala.Provider.Email.Protocol.Pop3.Mock

def init(bot_params) do
{
:ok,
bot_params
Map.put(
bot_params, :private, %{
mail_fetcher_module: (Mix.env() == :test &&@pop3_mock || @pop3)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

&&@pop3_mock - это какой-то особый синтаксис? непонятно немного

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

&&@pop3_mock -> && @pop3_mock

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Какая-то императивная магия

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вика поправила

}
)
}
end
end
41 changes: 41 additions & 0 deletions lib/agala_email_receiver.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
defmodule Agala.Provider.Email.Receiver do
@moduledoc """
Module providing email connection fetch.
"""
use Agala.Bot.Receiver
alias Agala.BotParams
@mail_proto Agala.Provider.Email.Protocol.Pop3.Mock

def get_updates(notify_with, bot_params = %BotParams{}) do
mail_proto = private_options(bot_params)
{:ok, client} = mail_proto.connect(mail_options(bot_params))
{:ok, mails} = mail_proto.scan(client)

Enum.map(mails, fn {id, _} ->
#@todo: use poolboy and asynk tasks
{:ok, bin_message} = mail_proto.retrieve(client, id)

mail_proto.parse_binary(bin_message)
|> resolve_mail(notify_with)
end)
end

defp mail_options(%BotParams{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Зачем этот метод вообще? Какой-то копипаст... Можно завернуть в provider_params.mail_params, или сделать Map.take...

provider_params: %{
login: login, email: email, password: password, server: server,
port: port
}
}
), do: %{email: email, password: password, server: server, port: port, login: login}

defp private_options(%BotParams{
private: %{
mail_fetcher_module: mail_fetcher_module
}
}
), do: mail_fetcher_module

defp resolve_mail({h, c}, notify_with) do
notify_with.({h, c})
end
end
41 changes: 41 additions & 0 deletions lib/protocol/pop3.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
defmodule Agala.Provider.Email.Protocol.Pop3 do
@moduledoc """
Implementation of Pop3 mail protocol for Agala framework.
Based on nico-amsterdam/pop3mail
"""

def connect(%{email: email, password: password, server: server, port: port, login: login}) do
:epop_client.connect(email, password, [{:addr, server},{:port, port},{:user, login},:ssl])
end

def scan(client) do
:epop_client.scan(client)
end

def retrieve(client, id) do
:epop_client.bin_retrieve(client, id)
end

def parse_binary(raw_binary) do
{:message, h, c} =
raw_binary
|> :epop_message.bin_parse
|> parse_content
|> parse_headers
{h, c}
end

def parse_headers({:message, headers, content}) do
parsed_headers =
headers
|> Enum.reduce(%{}, fn {:header, key, val}, acc ->
Map.put(acc, key, val)
end)
{:message, parsed_headers, content}
end

def parse_content({:message, headers, content}) do
parsed_content = Pop3mail.decode_body_content(headers, content)
{:message, headers, parsed_content}
end
end
35 changes: 35 additions & 0 deletions lib/protocol/pop3_mock.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
defmodule Agala.Provider.Email.Protocol.Pop3.Mock do
@moduledoc """
Implementation of mock module for Pop3 mail protocol of Agala framework.
For testing purposes
"""
alias Agala.Provider.Email.Protocol.Pop3

def connect(%{email: _, password: _, server: _, port: _, login: _}) do
{:ok,
{:sk, 'user', 'mail.example.com',
{:sslsocket, {:gen_tcp, "some_port", :tls_connection, :undefined},
self()}, 995, false, false, true}}
end

def scan(_client) do
{:ok, [{1, 1948}, {2, 1923}, {3, 1123}]}
end

def retrieve(_client, id) do
{:ok,
"To: <[email protected]@yandex.ru>\r\nFrom: Sender <[email protected]>\r\nSubject: =?UTF-8?B?0LLQvtC/0YDQvtGBINC/0L4g0LrRgNC10LTQuNGC0YM=?=\r\nDate: Tue, 30 Jan 2018 16:22:53 +0300\r\nUser-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101\r\n Thunderbird/52.5.2\r\nMIME-Version: 1.0\r\nContent-Type: text/plain; charset=\"utf-8\"; format=flowed\r\nContent-Transfer-Encoding: 8bit\r\nContent-Language: en-US\r\n\r\nmessage number #{id}\r\n\r\n"}
end

def parse_binary(raw_binary) do
Pop3.parse_binary(raw_binary)
end

def parse_headers({:message, headers, content}) do
Pop3.parse_headers({:message, headers, content})
end

def parse_content({:message, headers, content}) do
Pop3.parse_content({:message, headers, content})
end
end
4 changes: 3 additions & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ defmodule AgalaEmail.MixProject do
[
{:agala, "~> 2.0.2"},
{:ex_doc, "> 0.0.0", only: :dev},
{:credo, "~> 0.8", only: [:dev, :test]}
{:credo, "~> 0.8", only: [:dev, :test]},
{:pop3mail, "~> 1.3"},
{:erlpop, github: "nico-amsterdam/erlpop"}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 либы? зачем

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Разобрался, но хрень какая-то)

# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"},
]
Expand Down
4 changes: 4 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
"certifi": {:hex, :certifi, "2.0.0", "a0c0e475107135f76b8c1d5bc7efb33cd3815cb3cf3dea7aefdd174dabead064", [:rebar3], [], "hexpm"},
"credo": {:hex, :credo, "0.8.10", "261862bb7363247762e1063713bb85df2bbd84af8d8610d1272cd9c1943bba63", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}], "hexpm"},
"earmark": {:hex, :earmark, "1.2.4", "99b637c62a4d65a20a9fb674b8cffb8baa771c04605a80c911c4418c69b75439", [:mix], [], "hexpm"},
"erlpop": {:git, "https://github.com/nico-amsterdam/erlpop.git", "7a2ece268f5a57b9425b2bf7520a26326932b319", []},
"ex_doc": {:hex, :ex_doc, "0.18.2", "993e0a95e9fbb790ac54ea58e700b45b299bd48bc44b4ae0404f28161f37a83e", [:mix], [{:earmark, "~> 1.1", [hex: :earmark, repo: "hexpm", optional: false]}], "hexpm"},
"excoveralls": {:hex, :excoveralls, "0.7.5", "339e433e5d3bce09400dc8de7b9040741a409c93917849916c136a0f51fdc183", [:mix], [{:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: false]}, {:hackney, ">= 0.12.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"exjsx": {:hex, :exjsx, "4.0.0", "60548841e0212df401e38e63c0078ec57b33e7ea49b032c796ccad8cde794b5c", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, repo: "hexpm", optional: false]}], "hexpm"},
"hackney": {:hex, :hackney, "1.11.0", "4951ee019df102492dabba66a09e305f61919a8a183a7860236c0fde586134b6", [:rebar3], [{:certifi, "2.0.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "5.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
"iconv": {:hex, :iconv, "1.0.6", "3b424a80039059767f1037dc6a49ff07c2f88df14068c16dc938c4f377a77b4c", [:rebar3], [{:p1_utils, "1.0.10", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm"},
"idna": {:hex, :idna, "5.1.0", "d72b4effeb324ad5da3cab1767cb16b17939004e789d8c0ad5b70f3cea20c89a", [:rebar3], [{:unicode_util_compat, "0.3.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
"jsx": {:hex, :jsx, "2.8.3", "a05252d381885240744d955fbe3cf810504eb2567164824e19303ea59eef62cf", [:mix, :rebar3], [], "hexpm"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"},
"mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], [], "hexpm"},
"p1_utils": {:hex, :p1_utils, "1.0.10", "a6d6927114bac79cf6468a10824125492034af7071adc6ed5ebc4ddb443845d4", [:rebar3], [], "hexpm"},
"pop3mail": {:hex, :pop3mail, "1.3.0", "5eba88226a54572debe30667ceadd2f8e4ea104f3309fea8f74a768d71ee512c", [:mix], [], "hexpm"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], [], "hexpm"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.3.1", "a1f612a7b512638634a603c8f401892afbf99b8ce93a45041f8aaca99cadb85e", [:rebar3], [], "hexpm"},
}
22 changes: 22 additions & 0 deletions test/email_receiver_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
defmodule EmailReceiverTest do
use ExUnit.Case
doctest Agala.Provider.Email
alias Agala.BotParams
alias Agala.Provider.Email
alias Agala.Provider.Email.Receiver

@bot_configuration %BotParams{
provider_params: %{
login: "user",
password: "secure",
server: "mail.server.ru",
port: 995,
email: "[email protected]"
}
}

test "get_updates call applies handler" do
{:ok, bot_params} = Email.init(@bot_configuration)
assert [:ok, :ok, :ok] == Receiver.get_updates(fn _ -> :ok end, bot_params)
end
end
8 changes: 7 additions & 1 deletion test/email_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ defmodule EmailTest do
}
}

assert {:ok, ^bot_configuration} = Agala.Provider.Email.init(bot_configuration)
expected_bot_configuration = Map.put(
bot_configuration, :private, %{
mail_fetcher_module: Agala.Provider.Email.Protocol.Pop3.Mock
}
)

assert {:ok, ^expected_bot_configuration} = Agala.Provider.Email.init(bot_configuration)
end
end
63 changes: 63 additions & 0 deletions test/protocol/pop3_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
defmodule Email.Protocol.Pop3Test do
use ExUnit.Case
doctest Agala.Provider.Email.Protocol.Pop3
alias Agala.Provider.Email.Protocol.Pop3

test "parse_headers returns map of headers" do
exp_result = %{
"To" => "<[email protected]>",
"From" => "Sender <[email protected]>",
"Subject" =>
"=?UTF-8?B?0LLQvtC/0YDQvtGBINC/0L4g0LrRgNC10LTQuNGC0YM=?=",
"Message-ID" => "<[email protected]>",
"Date" => "Tue, 30 Jan 2018 16:22:53 +0300",
"User-Agent" =>
"Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.5.2",
"MIME-Version" => "1.0",
"Content-Type" => "text/plain; charset=\"utf-8\"; format=flowed",
"Content-Transfer-Encoding" => "8bit",
"Content-Language" => "en-US"
}
assert {:message, ^exp_result, _} = Pop3.parse_headers({:message, mock_headers(), mock_content()})
end

test "parse_content returns list of parts" do
exp_result = [
%Pop3mail.Part{
boundary: "",
charset: "utf-8",
content: "пожалуйста не присылайте коллекторов\r\n\r\n",
content_id: "",
content_location: "",
filename: "",
filename_charset: "us-ascii",
index: 1,
inline: nil,
media_type: "text/plain",
path: ""
}
]
assert {:message, _, ^exp_result} = Pop3.parse_content({:message, mock_headers(), mock_content()})
end

defp mock_headers() do
[
{:header, "To", "<[email protected]>"},
{:header, "From", "Sender <[email protected]>"},
{:header, "Subject",
"=?UTF-8?B?0LLQvtC/0YDQvtGBINC/0L4g0LrRgNC10LTQuNGC0YM=?="},
{:header, "Message-ID", "<[email protected]>"},
{:header, "Date", "Tue, 30 Jan 2018 16:22:53 +0300"},
{:header, "User-Agent",
"Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.5.2"},
{:header, "MIME-Version", "1.0"},
{:header, "Content-Type", "text/plain; charset=\"utf-8\"; format=flowed"},
{:header, "Content-Transfer-Encoding", "8bit"},
{:header, "Content-Language", "en-US"}
]
end

defp mock_content() do
"пожалуйста не присылайте коллекторов\r\n\r\n"
end
end