modificata logica parametri email

This commit is contained in:
2025-09-10 17:02:41 +02:00
parent f1f7872edd
commit a4475ee6a5
9 changed files with 374 additions and 108 deletions

View File

@ -1,30 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<config>
<fieldset label="COM_CIRCOLARI" name="circolari">
<field
name="email_oggetto"
type="text"
label="Oggetto email"
description="Testo email diretta ai docenti per la firma"
rows="8"
cols="60"
filter="raw" />
<field
name="email_testo"
type="textarea"
label="Testo email"
description="Testo email diretta ai docenti per la firma"
rows="8"
cols="60"
filter="raw" />
<field
name="dirigente_nome"
type="text"
label="Nominativo Dirigente"
description="Nominativo del Dirigente"
size="40" />
</fieldset>
<fieldset name="permissions" description="JCONFIG_PERMISSIONS_DESC"
label="JCONFIG_PERMISSIONS_LABEL">
<field name="rules" type="rules" component="com_circolari" class="inputbox" filter="rules"

View File

@ -50,7 +50,7 @@
showon="firma_obbligatoria:1" />
<field name="notify" type="radio"
label="Invia email"
description="Se Sì, invia subito una email ai gruppi selezionati"
description="Se Sì, invia subito una email ai gruppi selezionati dopo aver salvato"
default="0"
filter="unset"
showon="firma_obbligatoria:1"

View File

@ -29,4 +29,32 @@
</field>
<field name="version_note" type="text" label="JGLOBAL_FIELD_VERSION_NOTE_LABEL" description="JGLOBAL_FIELD_VERSION_NOTE_DESC" class="inputbox" size="45" labelclass="control-label"/>
</fieldset>
<fieldset name="mail" label="Email">
<field
name="email_subject"
type="text"
label="Oggetto email"
description="Oggetto della mail di notifica; supporta {TITOLO}, {SCADENZA}, {DIRIGENTE}."
size="60"
/>
<field
name="email_body"
type="textarea"
label="Testo email"
description="Corpo della mail; supporta {NOME}, {TITOLO}, {SCADENZA}, {LINK}, {DIRIGENTE}."
rows="10" cols="60"
class="span-12 monospace"
filter="raw"
/>
<field
name="dirigente_nome"
type="text"
label="Nominativo dirigente"
description="Firma/mail footer, usato come {DIRIGENTE}."
size="40"
/>
</fieldset>
</form>

View File

@ -0,0 +1,4 @@
ALTER TABLE `#__circolari_firmetipi`
ADD COLUMN `email_subject` VARCHAR(190) NULL AFTER `bottoni_firma`,
ADD COLUMN `email_body` MEDIUMTEXT NULL AFTER `email_subject`,
ADD COLUMN `dirigente_nome` VARCHAR(190) NULL AFTER `email_body`;

View File

@ -1,61 +1,225 @@
<?php
/**
* @version CVS: 1.0.0
* @package Com_Circolari
* @author Tommaso Cippitelli <tommaso.cippitelli@protocollicreativi.it>
* @copyright 2025 Tommaso Cippitelli
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Pcrt\Component\Circolari\Administrator\Controller;
namespace Pcrt\Component\Circolari\Administrator\Service;
\defined('_JEXEC') or die;
use Joomla\CMS\MVC\Controller\FormController;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Pcrt\Component\Circolari\Administrator\Service\Notifier;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Uri\Uri;
/**
* Circolare controller class.
*
* @since 1.0.0
* Invio notifiche email per le circolari.
* - Oggetto/Testo/Dirigente presi dalla tipologia firma (#__circolari_firmetipi).
* - Destinatari presi dalla pivot #__circolari_usergroups (can_firmare=1 o required=1).
* - Link frontend SEF anche se invocato da admin.
*/
class CircolareController extends FormController
class Notifier
{
protected $view_list = 'circolares';
protected $view_item = 'circolare';
public function __construct($config = array(), MVCFactoryInterface $factory = null, $app = null, $input = null)
/**
* Invia le email per la circolare $id.
*
* @param int $id ID circolare
* @param array $opts ['onlyIfFirmaObbligatoria' => true] Se true invia solo se firma_obbligatoria=1
* @return int Numero di email inviate con successo
*/
public function sendForCircolare(int $id, array $opts = []): int
{
parent::__construct($config, $factory, $app, $input);
$this->registerTask('apply', 'save');
$this->registerTask('save2new', 'save');
$onlyIfFirmaObbl = $opts['onlyIfFirmaObbligatoria'] ?? true;
$db = Factory::getContainer()->get('DatabaseDriver');
$row = $db->setQuery(
$db->getQuery(true)
->select('*')
->from('#__circolari')
->where('id=' . (int) $id)
)->loadObject();
if (!$row) {
return 0;
}
if ($onlyIfFirmaObbl && (int) ($row->firma_obbligatoria ?? 0) !== 1) {
return 0;
}
// Gruppi destinatari dalla pivot
$groups = $this->getGroupIdsFromPivot($id);
if (!$groups) {
return 0;
}
// Carica la tipologia di firma per subject/body/dirigente
$firmatipo = null;
if (!empty($row->tipologia_firma_id)) {
$firmatipo = $db->setQuery(
$db->getQuery(true)
->select('email_subject, email_body, dirigente_nome')
->from('#__circolari_firmetipi')
->where('id = ' . (int) $row->tipologia_firma_id)
)->loadObject();
}
// Link ASSOLUTO al FRONTEND (dettaglio circolare)
$link = $this->buildFrontendLink((int) $id);
// Scadenza formattata
$scadStr = '';
if (!empty($row->scadenza)) {
try {
$scadStr = (new \DateTime((string) $row->scadenza))->format('d/m/Y H:i');
} catch (\Throwable $e) {
$scadStr = '';
}
}
// Soggetto email (con placeholder)
$dirigenteName = (string) ($firmatipo->dirigente_nome ?? '');
$subjectTpl = (string) ($firmatipo->email_subject ?? '');
$subject = $subjectTpl !== ''
? strtr($subjectTpl, [
'{TITOLO}' => (string) $row->title,
'{SCADENZA}' => $scadStr !== '' ? $scadStr : '-',
'{DIRIGENTE}' => $dirigenteName,
])
: ('Nuova circolare: ' . (string) $row->title);
// Corpo email (testo) con placeholder
$textTpl = (string) ($firmatipo->email_body ?? '');
if ($textTpl === '') {
$textTpl = <<<TXT
Ciao {NOME},
è stata pubblicata/aggiornata una circolare che richiede la tua firma:
{TITOLO}
Scadenza firma: {SCADENZA}
Link: {LINK}
{DIRIGENTE}
TXT;
}
// Destinatari: utenti nei gruppi, non bloccati, con email
$q = $db->getQuery(true)
->select('u.id, u.name, u.email')
->from('#__users AS u')
->join('INNER', '#__user_usergroup_map AS m ON m.user_id = u.id')
->where('m.group_id IN (' . implode(',', array_map('intval', $groups)) . ')')
->where('u.block = 0')
->where("u.email <> ''")
->group('u.id');
$recipients = (array) $db->setQuery($q)->loadObjectList();
if (!$recipients) {
return 0;
}
// Mittente da Configurazione Globale
$config = Factory::getConfig();
$from = (string) $config->get('mailfrom');
$fromN = (string) $config->get('fromname');
$sent = 0;
foreach ($recipients as $r) {
$pairs = [
'{NOME}' => (string) $r->name,
'{TITOLO}' => (string) $row->title,
'{SCADENZA}' => $scadStr !== '' ? $scadStr : '-',
'{LINK}' => $link,
'{DIRIGENTE}' => $dirigenteName,
];
$mailer = Factory::getMailer();
$mailer->setSender([$from, $fromN]);
$mailer->addRecipient((string) $r->email);
$mailer->setSubject($subject);
$mailer->isHtml(false); // imposta true se vuoi usare un template HTML
$mailer->setBody(strtr($textTpl, $pairs));
try {
$ok = $mailer->send();
if ($ok === true) {
$sent++;
}
} catch (\Throwable $e) {
// opzionale: log
}
}
return $sent;
}
/**
* ID gruppi abilitati alla firma dalla pivot #__circolari_usergroups
* Regola: can_firmare=1 OR required=1; fallback a tutti i gruppi mappati.
*/
private function getGroupIdsFromPivot(int $circolareId): array
{
$db = Factory::getContainer()->get('DatabaseDriver');
// Preferisci can_firmare=1 O required=1
$q = $db->getQuery(true)
->select('DISTINCT ug.usergroup_id')
->from($db->quoteName('#__circolari_usergroups', 'ug'))
->where('ug.circolare_id = ' . (int) $circolareId)
->where('(ug.can_firmare = 1 OR ug.required = 1)');
$ids = array_map('intval', (array) $db->setQuery($q)->loadColumn());
public function save($key = null, $urlVar = null)
{
$app = \Joomla\CMS\Factory::getApplication();
$input = $app->input;
$post = $input->get('jform', [], 'array');
$notify= (int)($post['notify'] ?? 0);
$result = parent::save($key, $urlVar);
if ($result && $notify) {
$model = $this->getModel('Circolare');
$id = (int) $model->getState($model->getName().'.id') ?: (int)($post['id'] ?? 0);
if ($id <= 0) {
$db = \Joomla\CMS\Factory::getContainer()->get('DatabaseDriver');
$id = (int) $db->insertid();
}
if ($id > 0) {
(new Notifier())->sendForCircolare($id, ['onlyIfFirmaObbligatoria' => true]);
// Fallback: tutti i gruppi mappati
if (!$ids) {
$q = $db->getQuery(true)
->select('DISTINCT ug.usergroup_id')
->from($db->quoteName('#__circolari_usergroups', 'ug'))
->where('ug.circolare_id = ' . (int) $circolareId);
$ids = array_map('intval', (array) $db->setQuery($q)->loadColumn());
}
return array_values(array_unique(array_filter($ids, static fn($v) => $v > 0)));
}
/**
* Costruisce link ASSOLUTO al dettaglio circolare sul FRONTEND (SEF se esiste Itemid).
* Funziona anche se chiamato da admin (nessun menu.site nel container).
*/
private function buildFrontendLink(int $id): string
{
$db = Factory::getContainer()->get('DatabaseDriver');
// 1) prova Itemid per DETTAGLIO (view=circolare)
$q = $db->getQuery(true)
->select('id')
->from($db->quoteName('#__menu'))
->where('client_id = 0') // frontend
->where('published = 1')
->where('type = ' . $db->quote('component'))
->where('link LIKE ' . $db->quote('index.php?option=com_circolari&view=circolare%'))
->order('lft ASC');
$itemid = (int) $db->setQuery($q, 0, 1)->loadResult();
// 2) fallback: Itemid della LISTA (view=circolari)
if ($itemid === 0) {
$q = $db->getQuery(true)
->select('id')
->from($db->quoteName('#__menu'))
->where('client_id = 0')
->where('published = 1')
->where('type = ' . $db->quote('component'))
->where('link LIKE ' . $db->quote('index.php?option=com_circolari&view=circolari%'))
->order('lft ASC');
$itemid = (int) $db->setQuery($q, 0, 1)->loadResult();
}
// 3) rotta frontend
$rel = 'index.php?option=com_circolari&view=circolare&id=' . (int) $id . ($itemid ? '&Itemid=' . $itemid : '');
$url = Route::link('site', $rel, false);
// 4) assolutizza
if (strpos($url, 'http') !== 0) {
$url = Uri::root() . ltrim($url, '/');
}
return $url;
}
return $result;
}
}

View File

@ -19,42 +19,43 @@ use \Joomla\CMS\Language\Text;
$wa = $this->document->getWebAssetManager();
$wa->useScript('keepalive')
->useScript('form.validate');
->useScript('form.validate');
HTMLHelper::_('bootstrap.tooltip');
?>
<form
action="<?php echo Route::_('index.php?option=com_circolari&layout=edit&id=' . (int) $this->item->id); ?>"
method="post" enctype="multipart/form-data" name="adminForm" id="adminForm" class="form-validate form-horizontal">
action="<?php echo Route::_('index.php?option=com_circolari&layout=edit&id=' . (int) $this->item->id); ?>"
method="post" enctype="multipart/form-data" name="adminForm" id="adminForm" class="form-validate form-horizontal">
<?php echo HTMLHelper::_('uitab.startTabSet', 'myTab', array('active' => 'Circolari')); ?>
<?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'Circolari', Text::_('COM_CIRCOLARI_TAB_CIRCOLARI', true)); ?>
<div class="row-fluid">
<div class="col-md-12 form-horizontal">
<fieldset class="adminform">
<legend><?php echo Text::_('COM_CIRCOLARI_FIELDSET_CIRCOLARI'); ?></legend>
<?php echo $this->form->renderField('title'); ?>
<?php echo $this->form->renderField('alias'); ?>
<?php echo $this->form->renderField('categoria_id'); ?>
<?php echo $this->form->renderField('description'); ?>
<?php echo $this->form->renderField('attachment'); ?>
<?php echo $this->form->renderField('image'); ?>
<?php echo $this->form->renderField('firma_obbligatoria'); ?>
<?php echo $this->form->renderField('usergroup_ids'); ?>
<?php echo $this->form->renderField('scadenza'); ?>
<?php echo $this->form->renderField('notify'); ?>
</fieldset>
</div>
</div>
<?php echo HTMLHelper::_('uitab.endTab'); ?>
<?php echo HTMLHelper::_('uitab.startTabSet', 'myTab', array('active' => 'Circolari')); ?>
<?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'Circolari', Text::_('COM_CIRCOLARI_TAB_CIRCOLARI', true)); ?>
<div class="row-fluid">
<div class="col-md-12 form-horizontal">
<fieldset class="adminform">
<legend><?php echo Text::_('COM_CIRCOLARI_FIELDSET_CIRCOLARI'); ?></legend>
<?php echo $this->form->renderField('title'); ?>
<?php echo $this->form->renderField('alias'); ?>
<?php echo $this->form->renderField('categoria_id'); ?>
<?php echo $this->form->renderField('description'); ?>
<?php echo $this->form->renderField('attachment'); ?>
<?php echo $this->form->renderField('image'); ?>
<?php echo $this->form->renderField('firma_obbligatoria'); ?>
<?php echo $this->form->renderField('usergroup_ids'); ?>
<?php echo $this->form->renderField('tipologia_firma_id'); ?>
<?php echo $this->form->renderField('scadenza'); ?>
<?php echo $this->form->renderField('notify'); ?>
</fieldset>
</div>
</div>
<?php echo HTMLHelper::_('uitab.endTab'); ?>
<?php echo \Joomla\CMS\HTML\HTMLHelper::_('uitab.addTab', 'myTab', 'publishing', Text::_('Pubblicazione', true)); ?>
<div class="row-fluid">
<div class="col-md-12 form-horizontal">
<fieldset class="adminform">
<legend><?php echo Text::_('Pubblicazione'); ?></legend>
<?php echo $this->form->renderField('hits'); ?>
<?php echo $this->form->renderField('hits'); ?>
<?php echo $this->form->renderField('created'); ?>
<?php echo $this->form->renderField('created_by'); ?>
<?php echo $this->form->renderField('modified'); ?>
@ -65,13 +66,13 @@ HTMLHelper::_('bootstrap.tooltip');
</fieldset>
</div>
</div>
<?php echo \Joomla\CMS\HTML\HTMLHelper::_('uitab.endTab'); ?>
<?php echo \Joomla\CMS\HTML\HTMLHelper::_('uitab.endTab'); ?>
<input type="hidden" name="jform[id]" value="<?php echo isset($this->item->id) ? $this->item->id : ''; ?>" />
<input type="hidden" name="jform[state]" value="<?php echo isset($this->item->state) ? $this->item->state : ''; ?>" />
<?php echo HTMLHelper::_('uitab.endTabSet'); ?>
<input type="hidden" name="task" value="" />
<?php echo HTMLHelper::_('form.token'); ?>
<input type="hidden" name="jform[id]" value="<?php echo isset($this->item->id) ? $this->item->id : ''; ?>" />
<input type="hidden" name="jform[state]" value="<?php echo isset($this->item->state) ? $this->item->state : ''; ?>" />
<?php echo HTMLHelper::_('uitab.endTabSet'); ?>
<input type="hidden" name="task" value="" />
<?php echo HTMLHelper::_('form.token'); ?>
</form>
<?php

View File

@ -42,6 +42,20 @@ HTMLHelper::_('bootstrap.tooltip');
</div>
</div>
<?php echo HTMLHelper::_('uitab.endTab'); ?>
<?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'mail', JText::_('Mail')); ?>
<div class="row-fluid">
<div class="col-md-12 form-horizontal">
<fieldset class="adminform">
<legend><?php echo Text::_('Pubblicazione'); ?></legend>
<?php echo $this->form->renderField('email_subject');
echo $this->form->renderField('email_body');
echo $this->form->renderField('dirigente_nome'); ?>
</fieldset>
</div>
</div>
<?php echo HTMLHelper::_('uitab.endTab'); ?>
<input type="hidden" name="jform[id]" value="<?php echo isset($this->item->id) ? $this->item->id : ''; ?>" />
<input type="hidden" name="jform[state]" value="<?php echo isset($this->item->state) ? $this->item->state : ''; ?>" />