Skip to content

add mailer for collection invitations #2057

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions app/controllers/collections_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ def download_all

def share
if share_message.save
recipient = User.find_by(email: params[:user])
CollectionInvitationMailer.with(collection: @collection, recipient:).send_invitation.deliver_later
redirect_to @collection, notice: t('.success_notice')
else
redirect_to @collection, alert: share_message.errors.full_messages.join(', ')
Expand Down
12 changes: 12 additions & 0 deletions app/mailers/collection_invitation_mailer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

class CollectionInvitationMailer < ApplicationMailer
def send_invitation
@collection = params.fetch(:collection)
@recipient = params.fetch(:recipient)

I18n.with_locale(@recipient.preferred_locale || I18n.default_locale) do
mail(to: @recipient.email, subject: t('collections.invitation_mailer.subject', collection: @collection.title))
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

h3 = t('collections.invitation_mailer.greeting', user: @recipient.name)
p = t('collections.invitation_mailer.invitation_message', collection: @collection.title)
p = t('collections.invitation_mailer.collaboration_details')
p = t('collections.invitation_mailer.view_collection_instructions')
p = link_to t('collections.invitation_mailer.view_collection'), collection_url(@collection)
p = t('collections.invitation_mailer.contact_info')
p = t('collections.invitation_mailer.thank_you')
p = t('collections.invitation_mailer.team_signature', app_name: t('application.name'))
13 changes: 13 additions & 0 deletions app/views/collection_invitation_mailer/send_invitation.text.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
= t('collections.invitation_mailer.greeting', user: @recipient.name)

= t('collections.invitation_mailer.invitation_message', collection: @collection.title)

= t('collections.invitation_mailer.collaboration_details')

= t('collections.invitation_mailer.view_collection_instructions')
= collection_url(@collection)

= t('collections.invitation_mailer.contact_info')

= t('collections.invitation_mailer.thank_you')
= t('collections.invitation_mailer.team_signature', app_name: t('application.name'))
1 change: 1 addition & 0 deletions config/locales/de/views/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ de:
markdown_editor:
collapse: Editor zuklappen
expand: Editor aufklappen
name: CodeHarbor
navigation:
rails_admin: Rails Admin
session:
Expand Down
10 changes: 10 additions & 0 deletions config/locales/de/views/collections.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ de:
mine: Meine Sammlungen
public: Öffentliche Sammlungen
view_shared: Geteilte Sammlung anzeigen
invitation_mailer:
collaboration_details: Diese Zusammenarbeit ermöglicht es Ihnen, zum Inhalt dieser Sammlung beizutragen und bei der Verwaltung zu helfen.
contact_info: Wenn Sie Fragen zu dieser Einladung oder Ihrer Rolle als Mitarbeiter haben, wenden Sie sich bitte direkt an den Besitzer der Sammlung.
greeting: Hallo %{user},
invitation_message: Sie wurden eingeladen, an der Sammlung "%{collection}" mitzuarbeiten.
subject: 'Einladung zur Sammlung: %{collection}'
team_signature: "%{app_name} Team"
thank_you: Vielen Dank,
view_collection: Sammlung anzeigen
view_collection_instructions: 'Um die Sammlung anzuzeigen und mit Ihrer Zusammenarbeit zu beginnen, klicken Sie auf den Link unten:'
new:
header: Neue Sammlung
shared:
Expand Down
1 change: 1 addition & 0 deletions config/locales/en/views/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ en:
markdown_editor:
collapse: Collapse editor
expand: Expand editor
name: CodeHarbor
navigation:
rails_admin: Rails admin
session:
Expand Down
10 changes: 10 additions & 0 deletions config/locales/en/views/collections.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ en:
mine: My Collections
public: Public Collections
view_shared: View Shared Collection
invitation_mailer:
collaboration_details: This collaboration will allow you to contribute to and help manage this collection's content.
contact_info: If you have any questions about this invitation or your role as a collaborator, please contact the collection owner directly.
greeting: Hi %{user},
invitation_message: You've been invited to collaborate on the collection "%{collection}".
subject: 'Invitation to collection: %{collection}'
team_signature: "%{app_name} Team"
thank_you: Thank you,
view_collection: View collection
view_collection_instructions: 'To view the collection and get started with your collaboration, click the link below:'
new:
header: New Collection
shared:
Expand Down
17 changes: 17 additions & 0 deletions spec/controllers/collections_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -439,12 +439,24 @@
let(:post_request) { post :share, params: }
let(:params) { {id: collection.id, user: recipient.email} }
let(:recipient) { create(:user) }
let(:mailer) { instance_double(ActionMailer::MessageDelivery) }

before do
allow(CollectionInvitationMailer).to receive(:send_invitation).and_return(mailer)
allow(mailer).to receive(:deliver_later)
end

shared_examples 'success' do
it 'creates a message' do
expect { post_request }.to change(Message, :count).by(1)
end

it 'sends an invitation email' do

Check failure on line 454 in spec/controllers/collections_controller_spec.rb

View workflow job for this annotation

GitHub Actions / test

CollectionsController POST #share when sending second invite after a first message was deleted by recipient behaves like success sends an invitation email Failure/Error: expect(CollectionInvitationMailer).to have_received(:send_invitation).with(collection, recipient) (CollectionInvitationMailer (class)).send_invitation(#<Collection id: 65, created_at: "2025-07-02 19:05:00.504566000 +0000", updated_at: "2025-07-02 19:05...6000 +0000", title: "Some Collection", description: "Some Description", visibility_level: "private">, #<User id: 750, first_name: "John_1066", last_name: "Doe", created_at: "2025-07-02 19:05:00.484014000...RED], preferred_locale: nil, password_set: [FILTERED], status_group: "unknown", openai_api_key: nil>) expected: 1 time with arguments: (#<Collection id: 65, created_at: "2025-07-02 19:05:00.504566000 +0000", updated_at: "2025-07-02 19:05...6000 +0000", title: "Some Collection", description: "Some Description", visibility_level: "private">, #<User id: 750, first_name: "John_1066", last_name: "Doe", created_at: "2025-07-02 19:05:00.484014000...RED], preferred_locale: nil, password_set: [FILTERED], status_group: "unknown", openai_api_key: nil>) received: 0 times Shared Example Group: "success" called from ./spec/controllers/collections_controller_spec.rb:513

Check failure on line 454 in spec/controllers/collections_controller_spec.rb

View workflow job for this annotation

GitHub Actions / test

CollectionsController POST #share behaves like success sends an invitation email Failure/Error: expect(CollectionInvitationMailer).to have_received(:send_invitation).with(collection, recipient) (CollectionInvitationMailer (class)).send_invitation(#<Collection id: 56, created_at: "2025-07-02 19:04:59.623819000 +0000", updated_at: "2025-07-02 19:04...9000 +0000", title: "Some Collection", description: "Some Description", visibility_level: "private">, #<User id: 716, first_name: "John_1008", last_name: "Doe", created_at: "2025-07-02 19:04:59.654947000...RED], preferred_locale: nil, password_set: [FILTERED], status_group: "unknown", openai_api_key: nil>) expected: 1 time with arguments: (#<Collection id: 56, created_at: "2025-07-02 19:04:59.623819000 +0000", updated_at: "2025-07-02 19:04...9000 +0000", title: "Some Collection", description: "Some Description", visibility_level: "private">, #<User id: 716, first_name: "John_1008", last_name: "Doe", created_at: "2025-07-02 19:04:59.654947000...RED], preferred_locale: nil, password_set: [FILTERED], status_group: "unknown", openai_api_key: nil>) received: 0 times Shared Example Group: "success" called from ./spec/controllers/collections_controller_spec.rb:490
post_request
expect(CollectionInvitationMailer).to have_received(:send_invitation).with(collection, recipient)
expect(mailer).to have_received(:deliver_later)
end

it 'redirects to collection' do
post_request
expect(response).to redirect_to collection
Expand All @@ -460,6 +472,11 @@
expect { post_request }.not_to change(Message, :count)
end

it 'does not send an invitation email' do
post_request
expect(CollectionInvitationMailer).not_to have_received(:send_invitation)
end

it 'redirects to collection' do
post_request
expect(response).to redirect_to collection
Expand Down
37 changes: 37 additions & 0 deletions spec/mailers/collection_invitation_mailer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe CollectionInvitationMailer do
describe '#send_invitation' do
subject(:invitation_email) { described_class.with(collection:, recipient: user).send_invitation }

let(:collection) { create(:collection) }
let(:user) { create(:user) }

it 'sends an email to the correct recipient' do
expect(invitation_email.to).to include(user.email)
end

it 'has the correct subject' do
expect(invitation_email.subject).to include(collection.title)
end

it 'contains the correct content' do
expect(invitation_email.body.encoded).to include(user.name)
expect(invitation_email.body.encoded).to include(collection.title)
expect(invitation_email.body.encoded).to include('collaborate')
end

context 'with different locales' do
before do
user.update(preferred_locale: 'de')
end

it 'uses the user\'s preferred locale' do
expect(invitation_email.body.encoded).to include('Sammlung')
expect(invitation_email.subject).to include('Einladung zur Sammlung')
end
end
end
end
11 changes: 11 additions & 0 deletions spec/mailers/previews/collection_invitation_mailer_preview.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

require 'factory_bot_rails'

class CollectionInvitationMailerPreview < ActionMailer::Preview
def send_invitation
collection = FactoryBot.build(:collection, id: 1)
user = FactoryBot.build(:user, id: 2)
CollectionInvitationMailer.send_invitation(collection, user)
end
end
Loading