Add new invitation params (#20074)
* Add new invitation fields * SMTP enabled check * Update spec/requests/api/v1/admin/users_spec.rb Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Add devise_mailer spec * Add devise_mailer spec * Update spec/mailers/devise_mailer_spec.rb Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update spec/mailers/devise_mailer_spec.rb Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update spec/mailers/devise_mailer_spec.rb Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This commit is contained in:
parent
a679486572
commit
a079434397
10 changed files with 179 additions and 12 deletions
|
|
@ -15,6 +15,9 @@ module Admin
|
|||
|
||||
def create
|
||||
email = params.dig(:user, :email)
|
||||
custom_invite_subject = params.dig(:user, :custom_invite_subject)
|
||||
custom_invite_message = params.dig(:user, :custom_invite_message)
|
||||
custom_invite_footnote = params.dig(:user, :custom_invite_footnote)
|
||||
|
||||
if User.exists?(email: email.downcase, registered: true)
|
||||
flash[:error] = I18n.t("admin.invitations_controller.duplicate", email: email)
|
||||
|
|
@ -23,10 +26,16 @@ module Admin
|
|||
end
|
||||
|
||||
username = "#{email.split('@').first.gsub(/[^0-9a-z ]/i, '')}_#{rand(1000)}"
|
||||
User.invite!(email: email,
|
||||
username: username,
|
||||
profile_image: ::Images::ProfileImageGenerator.call,
|
||||
registered: false)
|
||||
User.invite!({ email: email,
|
||||
username: username,
|
||||
profile_image: ::Images::ProfileImageGenerator.call,
|
||||
registered: false },
|
||||
nil,
|
||||
{
|
||||
custom_invite_subject: custom_invite_subject,
|
||||
custom_invite_message: custom_invite_message,
|
||||
custom_invite_footnote: custom_invite_footnote
|
||||
})
|
||||
flash[:success] = I18n.t("admin.invitations_controller.create_success")
|
||||
redirect_to admin_invitations_path
|
||||
end
|
||||
|
|
@ -50,5 +59,17 @@ module Admin
|
|||
end
|
||||
redirect_to admin_invitations_path
|
||||
end
|
||||
|
||||
def configure_permitted_parameters
|
||||
devise_parameter_sanitizer.permit(:invite,
|
||||
keys: %i[email
|
||||
name
|
||||
username
|
||||
custom_invite_subject
|
||||
custom_invite_message
|
||||
custom_invite_footnote
|
||||
profile_image
|
||||
registered])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,7 +5,13 @@ module Api
|
|||
|
||||
def create
|
||||
# NOTE: We can add an inviting user here, e.g. User.invite!(current_user, user_params).
|
||||
User.invite!(user_params.merge(registered: false))
|
||||
options = {
|
||||
custom_invite_subject: params[:custom_invite_subject],
|
||||
custom_invite_message: params[:custom_invite_message],
|
||||
custom_invite_footnote: params[:custom_invite_footnote]
|
||||
}
|
||||
|
||||
User.invite!(user_params.merge(registered: false), nil, options)
|
||||
|
||||
head :ok
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,4 +10,13 @@ class DeviseMailer < Devise::Mailer
|
|||
"#{Settings::Community.community_name} <#{ForemInstance.from_email_address}>"
|
||||
ActionMailer::Base.default_url_options[:host] = Settings::General.app_domain
|
||||
end
|
||||
|
||||
# rubocop:disable Style/OptionHash
|
||||
def invitation_instructions(record, token, opts = {})
|
||||
@message = opts[:custom_invite_message]
|
||||
@footnote = opts[:custom_invite_footnote]
|
||||
headers = { subject: opts[:custom_invite_subject].presence || "Invitation Instructions" }
|
||||
super(record, token, opts.merge(headers))
|
||||
end
|
||||
# rubocop:enable Style/OptionHash
|
||||
end
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class User < ApplicationRecord
|
|||
|
||||
attr_accessor :scholar_email, :new_note, :note_for_current_role, :user_status, :merge_user_id,
|
||||
:add_credits, :remove_credits, :add_org_credits, :remove_org_credits, :ip_address,
|
||||
:current_password
|
||||
:current_password, :custom_invite_subject, :custom_invite_message, :custom_invite_footnote
|
||||
|
||||
acts_as_followable
|
||||
acts_as_follower
|
||||
|
|
|
|||
|
|
@ -30,6 +30,27 @@
|
|||
placeholder: "Email of invitee",
|
||||
required: true %>
|
||||
</div>
|
||||
<div class="crayons-field mt-6">
|
||||
<%= f.label :custom_invite_subject, "Subject (Optional)", class: "crayons-field__label" %>
|
||||
<%= f.text_field :custom_invite_subject,
|
||||
class: "crayons-textfield",
|
||||
placeholder: 'REPLACES "Invitation Instructions"',
|
||||
required: true %>
|
||||
</div>
|
||||
<div class="crayons-field mt-6">
|
||||
<%= f.label :custom_invite_message, "Custom Message (Optional)", class: "crayons-field__label" %>
|
||||
<%= f.text_area :custom_invite_message,
|
||||
class: "crayons-textfield",
|
||||
placeholder: "REPLACES INTRO: Hello... You have been invited to join...",
|
||||
required: true %>
|
||||
</div>
|
||||
<div class="crayons-field mt-6">
|
||||
<%= f.label :custom_invite_footnote, "Custom Footer (Optional)", class: "crayons-field__label" %>
|
||||
<%= f.text_field :custom_invite_footnote,
|
||||
class: "crayons-textfield",
|
||||
placeholder: "Comes right after invitation link",
|
||||
required: true %>
|
||||
</div>
|
||||
<div class="mt-6">
|
||||
<%= f.submit "Invite User", class: "crayons-btn" %>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,27 @@
|
|||
<p><%= t("devise.mailer.invitation_instructions.hello") %></p>
|
||||
|
||||
<p><%= t("devise.mailer.invitation_instructions.someone_invited_you", community_name: Settings::Community.community_name, url: root_url) %></p>
|
||||
<% if @message.present? %>
|
||||
<%= Markdown.new(@message).to_html.html_safe %>
|
||||
<% else %>
|
||||
<p><%= t("devise.mailer.invitation_instructions.hello") %></p>
|
||||
|
||||
<p><%= t("devise.mailer.invitation_instructions.accept_instructions") %>:</p>
|
||||
<p><%= t("devise.mailer.invitation_instructions.someone_invited_you", community_name: Settings::Community.community_name, url: root_url) %></p>
|
||||
|
||||
<p><%= link_to t("devise.mailer.invitation_instructions.accept"), accept_invitation_url(@resource, invitation_token: @token) %></p>
|
||||
<p><%= t("devise.mailer.invitation_instructions.accept_instructions") %>:</p>
|
||||
|
||||
<% end %>
|
||||
|
||||
<p><%= link_to t("devise.mailer.invitation_instructions.accept"),
|
||||
accept_invitation_url(@resource, invitation_token: @token),
|
||||
style: "color:white; background: #{Settings::UserExperience.primary_brand_color_hex}; border-radius: 8px; padding: 10px 20px; font-size: 1.33em; display: inline-block; margin: 8px 0; text-decoration: none; font-weight: bold;" %></p>
|
||||
|
||||
<% if @resource.invitation_due_at %>
|
||||
<p><%= t("devise.mailer.invitation_instructions.accept_until", due_date: l(@resource.invitation_due_at, format: :"devise.mailer.invitation_instructions.accept_until_format")) %></p>
|
||||
<% end %>
|
||||
|
||||
<p><%= t("devise.mailer.invitation_instructions.ignore") %></p>
|
||||
<div class="style: font-size: 0.9em">
|
||||
<% if @footnote.present? %>
|
||||
<%= Markdown.new(@footnote).to_html.html_safe %>
|
||||
<% end %>
|
||||
|
||||
<p><%= t("devise.mailer.invitation_instructions.ignore") %></p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -56,4 +56,52 @@ RSpec.describe DeviseMailer do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#invitation_instructions" do
|
||||
let(:token) { "some_token" }
|
||||
let(:custom_invite_message) { "Join our community!!" }
|
||||
let(:custom_invite_footnote) { "Looking forward to seeing you!!" }
|
||||
let(:custom_invite_subject) { "You've Been Invited" }
|
||||
|
||||
let(:opts) do
|
||||
{
|
||||
custom_invite_message: custom_invite_message,
|
||||
custom_invite_footnote: custom_invite_footnote,
|
||||
custom_invite_subject: custom_invite_subject
|
||||
}
|
||||
end
|
||||
|
||||
let(:email) { described_class.invitation_instructions(user, token, opts) }
|
||||
|
||||
before do
|
||||
allow(Settings::SMTP).to receive_messages(
|
||||
from_email_address: "custom_noreply@example.com",
|
||||
reply_to_email_address: "custom_reply@example.com",
|
||||
)
|
||||
end
|
||||
|
||||
it "uses the custom invite subject if provided" do
|
||||
expect(email.subject).to eq(custom_invite_subject)
|
||||
end
|
||||
|
||||
it "falls back to default subject if custom subject is not provided" do
|
||||
email_without_custom_subject = described_class.invitation_instructions(user, token, {})
|
||||
expect(email_without_custom_subject.subject).to eq("Invitation Instructions")
|
||||
end
|
||||
|
||||
it "includes the custom invite message if provided" do
|
||||
# Ensure your email view actually includes @message
|
||||
expect(email.to_s).to include(custom_invite_message)
|
||||
end
|
||||
|
||||
it "does not include overridden default message if invite message is provided" do
|
||||
# Ensure your email view actually includes @message
|
||||
expect(email.to_s).not_to include("<p>#{I18n.t('devise.mailer.invitation_instructions.accept_instructions')}")
|
||||
end
|
||||
|
||||
it "includes the custom invite footnote if provided" do
|
||||
# Ensure your email view actually includes @footnote
|
||||
expect(email.to_s).to include(custom_invite_footnote)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,14 @@
|
|||
module DeviseInvitable
|
||||
class MailerPreview < ActionMailer::Preview
|
||||
def invitation_instructions
|
||||
Devise.mailer.invitation_instructions(User.last, "faketoken")
|
||||
user = User.invite!(email: "test@email.com",
|
||||
username: "username")
|
||||
options = {
|
||||
custom_invite_subject: "Custom subject!!",
|
||||
custom_invite_message: "# Hey!\n\nJoin [our Forem](https://example.com).\n\n## Testing!",
|
||||
custom_invite_footnote: "Custom footnote! _Yay_"
|
||||
}
|
||||
Devise.mailer.invitation_instructions(user, "faketoken", options)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -40,6 +40,26 @@ RSpec.describe "/admin/member_manager/invitations" do
|
|||
expect(enqueued_jobs.first[:args]).to match(array_including("invitation_instructions"))
|
||||
end
|
||||
|
||||
it "enqueues an invitation email to be sent with custom subject", :aggregate_failures do
|
||||
allow(DeviseMailer).to receive(:invitation_instructions).and_call_original
|
||||
|
||||
assert_enqueued_with(job: Devise.mailer.delivery_job) do
|
||||
user_params = { email: "hey#{rand(1000)}@email.co",
|
||||
custom_invite_subject: "Custom Subject!",
|
||||
custom_invite_message: "**Custom message**",
|
||||
custom_invite_footnote: "Custom footnote" }
|
||||
post admin_invitations_path, params: { user: user_params }
|
||||
end
|
||||
|
||||
expect(DeviseMailer).to have_received(:invitation_instructions) do |_user, _token, args|
|
||||
expect(args).to include(
|
||||
custom_invite_subject: "Custom Subject!",
|
||||
custom_invite_message: "**Custom message**",
|
||||
)
|
||||
end
|
||||
expect(enqueued_jobs.first[:args]).to match(array_including("invitation_instructions"))
|
||||
end
|
||||
|
||||
it "does not create an invitation if a user with that email exists" do
|
||||
expect do
|
||||
post admin_invitations_path,
|
||||
|
|
|
|||
|
|
@ -49,6 +49,27 @@ RSpec.describe "/api/admin/users" do
|
|||
expect(response).to have_http_status(:ok)
|
||||
end
|
||||
|
||||
it "enqueues an invitation email to be sent with custom options", :aggregate_failures do
|
||||
allow(DeviseMailer).to receive(:invitation_instructions).and_call_original
|
||||
|
||||
assert_enqueued_with(job: Devise.mailer.delivery_job) do
|
||||
params = { email: "hey#{rand(1000)}@email.co",
|
||||
custom_invite_subject: "Custom Subject!",
|
||||
custom_invite_message: "**Custom message**",
|
||||
custom_invite_footnote: "Custom footnote" }
|
||||
|
||||
post api_admin_users_path, params: params, headers: headers
|
||||
end
|
||||
|
||||
expect(DeviseMailer).to have_received(:invitation_instructions) do |_user, _token, args|
|
||||
expect(args).to include(
|
||||
custom_invite_subject: "Custom Subject!",
|
||||
custom_invite_message: "**Custom message**",
|
||||
)
|
||||
end
|
||||
expect(enqueued_jobs.first[:args]).to match(array_including("invitation_instructions"))
|
||||
end
|
||||
|
||||
it "marks user as registered false" do
|
||||
post api_admin_users_path, params: params, headers: headers
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue