Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attachments: Support file data in attachment struct + mailgun attachment support #292

Merged
merged 3 commits into from Jul 13, 2017

Conversation

gitviola
Copy link
Contributor

As discussed in #286 @sbrink and I were working on an improved version of the attachment support:

Changes

  • supports |> put_attachment %Attachment{filename: "event.ics", data: "raw content..", content_type: "text/calendar"}
  • sets Attachment.data when using |> put_attachment "/hi.jpg" or |> put_attachment %Plug{..}
  • supports attachments in the mailgun and test adapter
  • updates the mandrill adapter to use the attachment.data

Todo

  • tests for the mailgun adapter (attachment support)

@randycoulman
Copy link
Contributor

How close is this PR to being ready to merge? I'm working on a project that needs to generate and attach vCards to e-mails, so being able to create an attachment from data rather than a file would be super helpful.

We use the SendGrid adapter, so I'm starting to work on a PR to add attachment support for that adapter today. I'd love it if I could base my work off of the code in this PR.

Thanks for all your work on this library!

Copy link
Contributor

@paulcsmith paulcsmith left a comment

Choose a reason for hiding this comment

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

Thank you so much for you work on this!

The description says:

# Supports...
|> put_attachment %Attachment{filename: "event.ics", data: "raw content..", content_type: "text/calendar"}

But I don't see documentation for that or a test, but maybe I missed it. If docs or tests are missing, could you add those? I think once that's in I can merge this and release a new RC.

Thank you so much!

@@ -112,7 +112,7 @@ defmodule Bamboo.MandrillAdapter do
%{
name: att.filename,
type: att.content_type,
content: Base.encode64(File.read!(att.path))
content: Base.encode64(att.data)
Copy link
Contributor

Choose a reason for hiding this comment

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

While we're in this PR, could you rename att to attachment?

@@ -52,4 +52,7 @@ defmodule Bamboo.TestAdapter do
def clean_assigns(email) do
%{email | assigns: :assigns_removed_for_testing}
end

@doc false
def supports_attachments?, do: true
Copy link
Contributor

Choose a reason for hiding this comment

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

Good catch!

Attachment.new("/path/to/attachment.png", filename: "image.png")
Attachment.new("/path/to/attachment.png", filename: "image.png", content_type: "image/png")
Attachment.new(params["file"]) # Where params["file"] is a %Plug.Upload
Attachment.new_from_file("/path/to/attachment.png")
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you change these to Bamboo.Attachment so it's clear this is coming from Bamboo?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also I think new is better here since there isn't a second function. Alternatively you could add new_from_data so there were two different functions. I'd probably prefer just new though

@@ -220,7 +220,10 @@ defmodule Bamboo.Email do
#...
end
"""
Copy link
Contributor

Choose a reason for hiding this comment

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

I think adding docs for sending data would be awesome here

Attachment.new("/path/to/attachment.png", filename: "image.png")
Attachment.new("/path/to/attachment.png", filename: "image.png", content_type: "image/png")
Attachment.new(params["file"]) # Where params["file"] is a %Plug.Upload
Attachment.new_from_file("/path/to/attachment.png")
Copy link
Contributor

Choose a reason for hiding this comment

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

Also I think new is better here since there isn't a second function. Alternatively you could add new_from_data so there were two different functions. I'd probably prefer just new though

@randycoulman
Copy link
Contributor

I tried this branch on something I was working on, and I noticed there were a number of test failures that will need to be resolved. It doesn't look like CircleCI is running builds right now, so there's no indication of a problem here.

From the test failures, I couldn't tell if the code was doing the right thing and the tests needed to be changed, or if the tests were right and the code was wrong. I suspect the latter, but I'm not confident enough in that to be able to suggest fixes.

@paulcsmith
Copy link
Contributor

Yeah I'm not sure what's up with Circle. I'll work on that. Busy with client work now, but hopefully in the next few days. In the meantime I can run it locally before merging to make sure it all works ok. @schurig are you seeing failures locally?

@gitviola
Copy link
Contributor Author

gitviola commented Jun 8, 2017

I'll do it asap! I remember that I fixed all tests. But I can't confirm at the moment.

@gitviola
Copy link
Contributor Author

I haven't found a way to test the attachments for the mailgun adapter. Can anyone help me with it?

It uses multipart as content type and I can't get the attachment by calling assert_receive {:fake_mailgun, struct} in the test.

@paulcsmith
Copy link
Contributor

@schurig I just came to check in and didn't realize you left that comment. Sorry about that. I would remove the changes from the MailgunAdapter and it's tests and instead do a separate PR for those. That way we can merge in the attachments changes and work on the adapters separately. Does that sound good?

@gitviola
Copy link
Contributor Author

@paulcsmith that sounds good!!

@gitviola
Copy link
Contributor Author

@paulcsmith ready for a 2nd review.

Copy link
Contributor

@paulcsmith paulcsmith left a comment

Choose a reason for hiding this comment

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

Just one small comment. Looks awesome. Thank you!

#...
end
"""
def put_attachment(%__MODULE__{attachments: attachments} = email, %Attachment{filename: _filename, data: _data} = attachment) do
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe you can shorten the pattern match of the attach meant to %Attachment{} since you wouldn't be able to initialize that struct without those fields

Copy link
Contributor Author

@gitviola gitviola Jul 13, 2017

Choose a reason for hiding this comment

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

You actually can. Then the values are set to nil because we don't specify anything as enforced keys:

iex(1)> %Bamboo.Attachment{}
%Bamboo.Attachment{content_type: nil, data: nil, filename: nil, path: nil}

But you're right - since we don't check the actual value it doesn't make sense for that check. But it would only make sense to put pass an Attachment struct with both keys (filename and data) specified in there. Do you think we should throw an error if one of it is empty?

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we have 2 functions. One for the happy path and another for attachments that are missing data and filename

def put_attachment(_email, %Attachment{filename: nil, data: nil} = attachment) do
  raise "You must pass a valid attachment, instead got: #{inspect attachment}"
end

def put_attachment(%__MODULE__{attachments: attachments} = email, %Attachment{} = attachment) do
  # happy path!
end

I think this would cover the common error case. We can add different error cases later if people run into things often. Thoughts?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@paulcsmith I've made the error messages more specific since it would still jump into the happy path if one of the params is nil. What do you think?

Copy link
Contributor

@paulcsmith paulcsmith left a comment

Choose a reason for hiding this comment

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

Just one small comment. I like the two error messages 👍

raise "You must provide a filename for the attachment."
end
def put_attachment(%__MODULE__{attachments: attachments} = email, %Attachment{data: nil}) do
raise "The attachment must contain data."
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you include the attachment in both error message so that it's easier to see what they passed in?

raise "The attachment must contain data, instead got: #{inspect attachment}"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point! Done. Also cleaned up a bit. There were some warnings about not used variables.

@paulcsmith
Copy link
Contributor

Wonderful work! Thanks for your first contribution to Bamboo!

@paulcsmith paulcsmith merged commit d09da6a into beam-community:master Jul 13, 2017
@gitviola gitviola deleted the develop branch July 13, 2017 20:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants