From 988bf9870ae5e76577b51deb219effbe23e6930e Mon Sep 17 00:00:00 2001 From: Jesse Shawl Date: Sat, 28 Oct 2023 12:12:35 -0500 Subject: [PATCH] Send attachments (#12) --- Gemfile | 2 -- Gemfile.lock | 5 ---- app/models/notification.rb | 16 +++++++++++-- ...141221_add_attachments_to_notifications.rb | 5 ++++ db/schema.rb | 3 ++- docs/http/index.md | 24 +++++++++++++++++-- spec/controllers/api/api_controller_spec.rb | 21 ++++++++++++++++ spec/fixtures/attachment.txt | 1 + spec/rails_helper.rb | 6 ++--- 9 files changed, 67 insertions(+), 16 deletions(-) create mode 100644 db/migrate/20231028141221_add_attachments_to_notifications.rb create mode 100644 spec/fixtures/attachment.txt diff --git a/Gemfile b/Gemfile index 1f644a0..c997bd4 100644 --- a/Gemfile +++ b/Gemfile @@ -51,8 +51,6 @@ group :test do gem 'rspec-rails' gem 'selenium-webdriver' gem 'webmock' - # Easy installation and use of web drivers to run system tests with browsers - gem 'webdrivers' gem 'simplecov', require: false end diff --git a/Gemfile.lock b/Gemfile.lock index b55db37..f1a00a9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -286,10 +286,6 @@ GEM activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) - webdrivers (5.2.0) - nokogiri (~> 1.6) - rubyzip (>= 1.3.0) - selenium-webdriver (~> 4.0) webmock (3.18.1) addressable (>= 2.8.0) crack (>= 0.3.2) @@ -329,7 +325,6 @@ DEPENDENCIES stripe tzinfo-data web-console (>= 4.1.0) - webdrivers webmock RUBY VERSION diff --git a/app/models/notification.rb b/app/models/notification.rb index 6cbb86a..2191572 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -14,6 +14,13 @@ def deliver SendGrid::Email.new(email: to), content ) + attachments.each do |a| + attachment = SendGrid::Attachment.new + attachment.content = a['content'] + attachment.filename = a['filename'] + attachment.type = a['type'] + mail.add_attachment(attachment) + end sg = SendGrid::API.new(api_key: Rails.application.credentials.sendgrid[:api_key]) sg.client.mail._('send').post(request_body: mail.to_json) end @@ -23,9 +30,14 @@ def self.from_params(params) notifications = emails.map do |email| user = User.find_or_initialize_by(email:) user.save(validate: false) - user.notifications.create!( - { to: email.squish }.merge(params.permit(:subject, :body)) + notification_params = { to: email.squish }.merge( + params.permit(:subject, :body, attachments: %i[ + content + type + filename + ]) ) + user.notifications.create!(notification_params) end if notifications.count == 1 notifications[0] diff --git a/db/migrate/20231028141221_add_attachments_to_notifications.rb b/db/migrate/20231028141221_add_attachments_to_notifications.rb new file mode 100644 index 0000000..22f293c --- /dev/null +++ b/db/migrate/20231028141221_add_attachments_to_notifications.rb @@ -0,0 +1,5 @@ +class AddAttachmentsToNotifications < ActiveRecord::Migration[6.1] + def change + add_column :notifications, :attachments, :json, default: [] + end +end diff --git a/db/schema.rb b/db/schema.rb index b2ce689..fece779 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2023_04_15_145356) do +ActiveRecord::Schema.define(version: 2023_10_28_141221) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -35,6 +35,7 @@ t.text "body" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false + t.json "attachments", default: [] t.index ["user_id"], name: "index_notifications_on_user_id" end diff --git a/docs/http/index.md b/docs/http/index.md index 6ff0875..eda41ca 100644 --- a/docs/http/index.md +++ b/docs/http/index.md @@ -16,18 +16,38 @@ The HTTP API is how emails are sent from Continuous Integration environments. |to|string|true| |subject|string|true| |body|string|false| +|attachments|array|false| + +#### Attachments + +|name|type|required|description| +|---|---|---| +|type|string|true|The content's MIME type| +|content|string|true|The Base64 encoded content of the attachment| +|filename|string|true|The attachment's filename| ### Example #### application/x-www-form-urlencoded ```bash curl --request POST 'https://www.cinotify.cc/api/notify' \ - -d "to=example@example.com&subject=building main&body=hello." + -d "to=example@example.com&subject=building main&body=hello.&attachments[][type]=text/plain&attachments[][content]=aGVsbG8sIHdvcmxkIQ==&attachments[][filename]=hello.txt" ``` #### json ```bash curl -X POST 'https://www.cinotify.cc/api/notify' \ -H "Content-Type: application/json" \ - -d '{"to":"example@example.com", "subject": "building main", "body":"hello."}' + -d '{ + "to": "example@example.com", + "subject": "building main", + "body": "hello.", + "attachments": [ + { + "type": "text/plain", + "content": "aGVsbG8sIHdvcmxkIQ==", + "filename": "hello.txt" + } + ] + }' ``` diff --git a/spec/controllers/api/api_controller_spec.rb b/spec/controllers/api/api_controller_spec.rb index def4910..3e980d7 100644 --- a/spec/controllers/api/api_controller_spec.rb +++ b/spec/controllers/api/api_controller_spec.rb @@ -56,4 +56,25 @@ } end.to change { Notification.count }.by(2) end + it 'supports attachments' do + stub_request(:post, 'https://api.sendgrid.com/v3/mail/send') + .with( + body: '{"from":{"email":"app@cinotify.cc"},"subject":"hello w/ attachments","personalizations":[{"to":[{"email":"example@example.com"}]}],"content":[{"type":"text/plain","value":"Please see the attached file(s)"}],"attachments":[{"content":"VGhpcyBpcyBhIGZpbGUgdG8gYmUgYXR0YWNoZWQgdG8gYW4gZW1haWwuCg==","type":"text/plain","filename":"attachment.txt"}]}' + ) + .to_return(status: 200, body: '[]', headers: {}) + expect do + post :notify, params: { + to: 'example@example.com', + subject: 'hello w/ attachments', + body: 'Please see the attached file(s)', + attachments: [ + { + content: Base64.strict_encode64(File.read("spec/fixtures/attachment.txt")), + type: "text/plain", + filename: "attachment.txt" + } + ] + } + end.to change { Notification.count }.by(1) + end end diff --git a/spec/fixtures/attachment.txt b/spec/fixtures/attachment.txt new file mode 100644 index 0000000..b6d8171 --- /dev/null +++ b/spec/fixtures/attachment.txt @@ -0,0 +1 @@ +This is a file to be attached to an email. diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index d5502fc..2092dd7 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -9,10 +9,8 @@ require 'rspec/rails' require 'capybara/rails' require 'capybara/rspec' -require 'webdrivers/chromedriver' - -Capybara.default_driver = :selenium_chrome_headless -Capybara.javascript_driver = :selenium_chrome_headless +Capybara.default_driver = :selenium_headless +Capybara.javascript_driver = :selenium_headless require 'webmock/rspec' WebMock.disable_net_connect!(allow: %r{(__identify__|shutdown|session|chromedriver.storage.googleapis.com)}) # Add additional requires below this line. Rails is not loaded until this point!