Aggiunge fascia oraria, prova manuale obbligatoria e cruscotto invii email.
Le campagne rispettano orario e giorni lavorativi, richiedono una mail di test con dati inseriti a mano prima dell'invio massivo e offrono una dashboard per monitorare l'avanzamento. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,12 +1,20 @@
|
||||
class MailingsController < ApplicationController
|
||||
before_action :require_current_project!
|
||||
before_action :set_mailing, only: %i[show edit update destroy queue test_send refresh_recipients update_recipients preview]
|
||||
before_action :set_mailing, only: %i[show edit update destroy queue test_send test_preview refresh_recipients update_recipients preview]
|
||||
before_action :load_form_collections, only: %i[new create edit update]
|
||||
|
||||
def index
|
||||
@page_title = "Email"
|
||||
redirect_to dashboard_mailings_path
|
||||
end
|
||||
|
||||
def dashboard
|
||||
@page_title = "Invii email"
|
||||
@mailings = Mailing.for_project(current_project).includes(:mail_identity).recent
|
||||
@mail_identities_count = MailIdentity.active.count
|
||||
@active_mailings = @mailings.select(&:sending?)
|
||||
@paused_mailings = @active_mailings.select { |mailing| mailing.next_send_at.present? && mailing.next_send_at > Time.current }
|
||||
@completed_today = @mailings.count { |mailing| mailing.sent? && mailing.completed_at&.to_date == Time.zone.today }
|
||||
@failed_open = @mailings.sum(&:failed_count)
|
||||
end
|
||||
|
||||
def new
|
||||
@@ -19,6 +27,8 @@ class MailingsController < ApplicationController
|
||||
mail_identity: identity,
|
||||
audience: "to_send",
|
||||
interval_seconds: 0,
|
||||
send_window_start_minutes: 10 * 60,
|
||||
send_window_end_minutes: 18 * 60,
|
||||
ab_assignment: "from_record",
|
||||
name: "Invio #{l(Time.zone.today)}",
|
||||
subject: template&.subject,
|
||||
@@ -47,6 +57,7 @@ class MailingsController < ApplicationController
|
||||
context = @preview_recipient&.merge_context || { project: current_project, ab_variant: @preview_variant }
|
||||
@preview_html = MailMerge.render(@mailing.body_for(@preview_variant), **context)
|
||||
@preview_subject = MailMerge.render(@mailing.subject_for(@preview_variant), **context)
|
||||
assign_test_preview
|
||||
end
|
||||
|
||||
def edit
|
||||
@@ -76,12 +87,12 @@ class MailingsController < ApplicationController
|
||||
|
||||
def destroy
|
||||
unless @mailing.draft?
|
||||
redirect_to mailings_path, alert: "Puoi eliminare solo le bozze."
|
||||
redirect_to dashboard_mailings_path, alert: "Puoi eliminare solo le bozze."
|
||||
return
|
||||
end
|
||||
|
||||
@mailing.destroy!
|
||||
redirect_to mailings_path, notice: "Invio eliminato."
|
||||
redirect_to dashboard_mailings_path, notice: "Invio eliminato."
|
||||
end
|
||||
|
||||
def refresh_recipients
|
||||
@@ -117,31 +128,39 @@ class MailingsController < ApplicationController
|
||||
redirect_to @mailing, alert: "Questo invio è già stato concluso."
|
||||
return
|
||||
end
|
||||
unless @mailing.tested?
|
||||
redirect_to @mailing, alert: "Prima di autorizzare l'invio di massa, manda una email di prova con dati di test."
|
||||
return
|
||||
end
|
||||
|
||||
@mailing.queue_send!
|
||||
redirect_to @mailing, notice: "Invio avviato. Le email partono in background#{@mailing.interval_seconds.positive? ? " con pausa di #{@mailing.interval_seconds}s" : ""}."
|
||||
redirect_to dashboard_mailings_path, notice: queue_notice(@mailing)
|
||||
rescue StandardError => e
|
||||
redirect_to @mailing, alert: e.message
|
||||
end
|
||||
|
||||
def test_send
|
||||
recipient = preview_recipient
|
||||
unless recipient&.email_ok?
|
||||
redirect_to @mailing, alert: "Nessun destinatario valido da usare come dati di prova."
|
||||
assign_test_preview
|
||||
to = @test_to.to_s.strip
|
||||
unless to.match?(URI::MailTo::EMAIL_REGEXP)
|
||||
redirect_to @mailing, alert: "Inserisci un indirizzo email valido per la prova."
|
||||
return
|
||||
end
|
||||
|
||||
variant = preview_variant
|
||||
html = MailMerge.render(@mailing.body_for(variant), **recipient.merge_context.merge(ab_variant: variant))
|
||||
subject = "[TEST#{@mailing.ab_test? ? " #{variant}" : ""}] #{MailMerge.render(@mailing.subject_for(variant), **recipient.merge_context.merge(ab_variant: variant))}"
|
||||
test_recipient = recipient.dup
|
||||
test_recipient.email = current_user.email
|
||||
CampaignMailer.outreach(test_recipient, html: html, subject: subject).deliver_now
|
||||
redirect_to mailing_path(@mailing, recipient_id: recipient.id, variant: variant), notice: "Email di prova (#{@mailing.ab_test? ? "variante #{variant}" : "unica"}) inviata a #{current_user.email}."
|
||||
html = @test_preview_html
|
||||
subject = "[TEST#{@mailing.ab_test? ? " #{@test_variant}" : ""}] #{@test_preview_subject}"
|
||||
recipient = Mailings::TestRecipient.new(mailing: @mailing, email: to)
|
||||
CampaignMailer.outreach(recipient, html: html, subject: subject).deliver_now
|
||||
@mailing.update!(test_sent_at: Time.current, test_sent_to: to)
|
||||
redirect_to @mailing, notice: "Prova inviata subito a #{to}. Controlla l'output e, se è corretto, autorizza l'invio di massa."
|
||||
rescue StandardError => e
|
||||
redirect_to @mailing, alert: "Invio di prova non riuscito: #{e.message}"
|
||||
end
|
||||
|
||||
def test_preview
|
||||
assign_test_preview
|
||||
end
|
||||
|
||||
def preview
|
||||
redirect_to mailing_path(@mailing, recipient_id: params[:recipient_id])
|
||||
end
|
||||
@@ -161,10 +180,19 @@ class MailingsController < ApplicationController
|
||||
params.require(:mailing).permit(
|
||||
:name, :mail_identity_id, :mail_template_id, :mail_template_b_id, :audience,
|
||||
:subject, :body_html, :subject_b, :body_html_b, :ab_test, :ab_assignment,
|
||||
:interval_seconds, files: []
|
||||
:interval_seconds, :send_window_enabled, :send_window_start_tod, :send_window_end_tod, files: []
|
||||
)
|
||||
end
|
||||
|
||||
def queue_notice(mailing)
|
||||
pause = mailing.interval_seconds.positive? ? " con pausa di #{mailing.interval_seconds}s" : ""
|
||||
if mailing.send_window_enabled? && mailing.next_send_at && mailing.next_send_at > Time.current
|
||||
"Invio avviato. La prima email partirà #{I18n.l(mailing.next_send_at, format: :long)} (fascia #{mailing.send_window_label}#{pause})."
|
||||
else
|
||||
"Invio avviato. Le email partono in background#{pause}."
|
||||
end
|
||||
end
|
||||
|
||||
def apply_template_if_needed
|
||||
copy_template_if_blank(params.dig(:mailing, :mail_template_id), :subject, :body_html)
|
||||
copy_template_if_blank(params.dig(:mailing, :mail_template_b_id), :subject_b, :body_html_b)
|
||||
@@ -202,4 +230,35 @@ class MailingsController < ApplicationController
|
||||
|
||||
preview_recipient&.ab_variant.presence_in(%w[A B]) || "A"
|
||||
end
|
||||
|
||||
def assign_test_preview
|
||||
@test_to = test_send_params[:to].presence || current_user.email
|
||||
@test_variant = test_send_params[:variant].to_s.upcase.presence_in(%w[A B]) || preview_variant
|
||||
@test_vars = default_test_vars.merge(test_vars_params)
|
||||
extras = @test_vars
|
||||
@test_preview_html = MailMerge.render(@mailing.body_for(@test_variant), extras: extras, project: current_project, ab_variant: @test_variant)
|
||||
@test_preview_subject = MailMerge.render(@mailing.subject_for(@test_variant), extras: extras, project: current_project, ab_variant: @test_variant)
|
||||
end
|
||||
|
||||
def default_test_vars
|
||||
source = preview_recipient
|
||||
if source
|
||||
MailMerge.variables_for(**source.merge_context.merge(ab_variant: preview_variant))
|
||||
else
|
||||
MailMerge.catalog.keys.index_with { "" }
|
||||
end
|
||||
end
|
||||
|
||||
def test_send_params
|
||||
params.permit(:to, :variant, :recipient_id)
|
||||
end
|
||||
|
||||
def test_vars_params
|
||||
raw = params[:vars]
|
||||
return {} unless raw.respond_to?(:to_unsafe_h) || raw.is_a?(Hash)
|
||||
|
||||
allowed = MailMerge.catalog.keys
|
||||
hash = raw.respond_to?(:to_unsafe_h) ? raw.to_unsafe_h : raw
|
||||
hash.stringify_keys.slice(*allowed).transform_values { |value| value.to_s }
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user