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 :load_form_collections, only: %i[new create edit update] def index @page_title = "Email" @mailings = Mailing.for_project(current_project).includes(:mail_identity).recent @mail_identities_count = MailIdentity.active.count end def new @page_title = "Nuovo invio" template = MailTemplate.for_project(current_project).order(:name).first identity = MailIdentity.active.ordered.first @mailing = Mailing.new( project: current_project, mail_template: template, mail_identity: identity, audience: "to_send", interval_seconds: 0, ab_assignment: "from_record", name: "Invio #{l(Time.zone.today)}", subject: template&.subject, body_html: template&.body_html ) end def create @mailing = Mailing.new(mailing_params) @mailing.project = current_project apply_template_if_needed if @mailing.save @mailing.rebuild_recipients! redirect_to @mailing, notice: "Bozza creata. Controlla i destinatari e poi invia." else @page_title = "Nuovo invio" render :new, status: :unprocessable_entity end end def show @page_title = @mailing.name @recipients = @mailing.mailing_recipients.includes(:organization, :contact).ordered @preview_recipient = preview_recipient @preview_variant = preview_variant 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) end def edit unless @mailing.editable? redirect_to @mailing, alert: "Questo invio non è più modificabile." return end @page_title = "Modifica invio" end def update unless @mailing.editable? redirect_to @mailing, alert: "Questo invio non è più modificabile." return end @mailing.assign_attributes(mailing_params) apply_template_if_needed if @mailing.save rebuild_recipients_if_needed redirect_to @mailing, notice: "Invio aggiornato." else @page_title = "Modifica invio" render :edit, status: :unprocessable_entity end end def destroy unless @mailing.draft? redirect_to mailings_path, alert: "Puoi eliminare solo le bozze." return end @mailing.destroy! redirect_to mailings_path, notice: "Invio eliminato." end def refresh_recipients unless @mailing.editable? redirect_to @mailing, alert: "Destinatari bloccati: l'invio è già partito." return end @mailing.rebuild_recipients! redirect_to @mailing, notice: "Lista destinatari aggiornata." end def update_recipients unless @mailing.editable? redirect_to @mailing, alert: "Non puoi più cambiare i destinatari." return end selected = Array(params[:pending_ids]).map(&:to_i) @mailing.mailing_recipients.where.not(status: %w[sent queued]).find_each do |recipient| if selected.include?(recipient.id) && recipient.email_ok? recipient.update!(status: "pending", skip_reason: nil) else reason = recipient.email_ok? ? "escluso dal check" : (recipient.skip_reason.presence || "email non valida") recipient.update!(status: "skipped", skip_reason: reason) end end redirect_to @mailing, notice: "Selezione destinatari salvata." end def queue unless @mailing.draft? || @mailing.sending? redirect_to @mailing, alert: "Questo invio è già stato concluso." 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" : ""}." 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." 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}." rescue StandardError => e redirect_to @mailing, alert: "Invio di prova non riuscito: #{e.message}" end def preview redirect_to mailing_path(@mailing, recipient_id: params[:recipient_id]) end private def set_mailing @mailing = Mailing.for_project(current_project).find(params[:id]) end def load_form_collections @mail_identities = MailIdentity.active.ordered @mail_templates = MailTemplate.for_project(current_project) end def mailing_params 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: [] ) end def apply_template_if_needed copy_template(params.dig(:mailing, :mail_template_id), :subject, :body_html, params[:use_template_content]) copy_template(params.dig(:mailing, :mail_template_b_id), :subject_b, :body_html_b, params[:use_template_b_content]) end def copy_template(template_id, subject_attr, body_attr, flag) return if template_id.blank? return unless ActiveModel::Type::Boolean.new.cast(flag) template = MailTemplate.for_project(current_project).find_by(id: template_id) return unless template @mailing.public_send("#{subject_attr}=", template.subject) @mailing.public_send("#{body_attr}=", template.body_html) end def rebuild_recipients_if_needed return unless @mailing.editable? return unless @mailing.saved_change_to_audience? || @mailing.saved_change_to_ab_test? || @mailing.saved_change_to_ab_assignment? @mailing.rebuild_recipients! end def preview_recipient if params[:recipient_id].present? @mailing.mailing_recipients.find_by(id: params[:recipient_id]) else @mailing.mailing_recipients.pending.ordered.first || @mailing.mailing_recipients.ordered.first end end def preview_variant requested = params[:variant].to_s.upcase return requested if requested.in?(%w[A B]) return "A" unless @mailing.ab_test? preview_recipient&.ab_variant.presence_in(%w[A B]) || "A" end end