mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-25 11:38:44 +02:00
N°918 - Translate placeholders in notifications (#506)
- Localization of date & time formats - Use of DataLocalizer (if present) - All placeholders can be used in the uploaded HTML template as well as in the notification "message"
This commit is contained in:
@@ -7,6 +7,7 @@ use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use Exception;
|
||||
use MetaModel;
|
||||
use utils;
|
||||
use Dict;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
@@ -23,11 +24,22 @@ class ActionEmailTest extends ItopDataTestCase
|
||||
|
||||
/** @var \ActionEmail|null Temp ActionEmail created for tests */
|
||||
protected static $oActionEmail = null;
|
||||
|
||||
/** @var \ormDocument|null Temp ormDocument for tests */
|
||||
protected static $oDocument = null;
|
||||
|
||||
/** @var \UserRequest|null Temp ormDocument for tests */
|
||||
protected static $oUserRequest = null;
|
||||
|
||||
/** @var string[] Dict formatted message, because the Dict class is not available in providers */
|
||||
protected static $aWarningMessages;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->RequireOnceItopFile('application/Html2Text.php');
|
||||
|
||||
static::$oActionEmail = MetaModel::NewObject('ActionEmail', [
|
||||
'name' => 'Test action',
|
||||
'status' => 'disabled',
|
||||
@@ -35,7 +47,27 @@ class ActionEmailTest extends ItopDataTestCase
|
||||
'subject' => 'Test subject',
|
||||
'body' => 'Test body',
|
||||
]);
|
||||
|
||||
$sHtml =
|
||||
<<<HTML
|
||||
<body>
|
||||
<table data-something-that-would-be-removed-by-the-sanitizer-through-ckeditor-but-that-will-stay-with-the-template="bar">
|
||||
<tr><td>Formatted eMail</td></tr>
|
||||
<tr><td>\$content\$</td></tr>
|
||||
</body>
|
||||
HTML
|
||||
;
|
||||
|
||||
static::$oActionEmail->DBInsert();
|
||||
static::$oDocument = new \ormDocument($sHtml, 'text/html', 'sample.html');
|
||||
static::$oUserRequest = MetaModel::NewObject('UserRequest', [
|
||||
'title' => 'Test UserRequest',
|
||||
'description' => '<p>Multi-line<br/>description</p>'
|
||||
]);
|
||||
|
||||
static::$aWarningMessages = [
|
||||
'warning-missing-content' => Dict::Format('ActionEmail:content_placeholder_missing', '$content$', Dict::S('Class:ActionEmail/Attribute:body'))
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,7 +109,6 @@ class ActionEmailTest extends ItopDataTestCase
|
||||
$this->assertEquals($sExpectedIdentifier, $sTestedIdentifier);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function GenerateIdentifierForHeadersProvider()
|
||||
@@ -88,4 +119,206 @@ class ActionEmailTest extends ItopDataTestCase
|
||||
'IncorrectHeaderName' => ['IncorrectHeaderName'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider prepareMessageContentProvider
|
||||
*/
|
||||
public function testPrepareMessageContent($sCurrentUserLanguage, $aActionFields, $aFieldsToCheck)
|
||||
{
|
||||
\Dict::SetUserLanguage($sCurrentUserLanguage);
|
||||
$aContext = ['this->object()' => static::$oUserRequest];
|
||||
$oActionEmail = MetaModel::NewObject('ActionEmail', [
|
||||
'name' => 'Test action',
|
||||
'status' => 'disabled',
|
||||
'from' => 'unit-test@openitop.org',
|
||||
'subject' => 'Test subject',
|
||||
'body' => 'Test body',
|
||||
]);
|
||||
foreach($aActionFields as $sCode => $value) {
|
||||
if ($sCode === 'html_template') {
|
||||
// special case since the data provider cannot create ormDocument objects
|
||||
$oActionEmail->Set($sCode, static::$oDocument);
|
||||
} else {
|
||||
$oActionEmail->Set($sCode, $value);
|
||||
}
|
||||
|
||||
}
|
||||
$oActionEmail->DBInsert();
|
||||
|
||||
$oOrg = $this->CreateOrganization('testPrepareMessageContent');
|
||||
|
||||
$oContact1 = MetaModel::NewObject('Person', [
|
||||
'name' => 'Person 1',
|
||||
'first_name' => 'PrepareMessageContent',
|
||||
'org_id' => $oOrg->GetKey(),
|
||||
'email' => 'some.valid@email.com',
|
||||
'notify' => 'yes',
|
||||
]);
|
||||
$oContact1->DBInsert();
|
||||
|
||||
|
||||
$oContact2 = MetaModel::NewObject('Person', [
|
||||
'name' => 'Person 2',
|
||||
'first_name' => 'PrepareMessageContent',
|
||||
'org_id' => $oOrg->GetKey(),
|
||||
'email' => 'some.valid2@email.com',
|
||||
'notify' => 'no',
|
||||
]);
|
||||
$oContact2->DBInsert();
|
||||
|
||||
$oLog = null;
|
||||
|
||||
$aEmailContent = $this->InvokeNonPublicMethod('\ActionEmail', 'PrepareMessageContent', $oActionEmail, [$aContext, &$oLog]);
|
||||
// Normalize the content of the body to simplify the comparison, useful when status == test
|
||||
$aEmailContent['body'] = preg_replace('/title="[^"]+"/', 'title="****"', $aEmailContent['body']);
|
||||
$aEmailContent['body'] = preg_replace('/class="object-ref-link" href="[^"]+"/', 'class="object-ref-link" href="****"', $aEmailContent['body']);
|
||||
$aEmailContent['body'] = preg_replace('/References: <[^>]+>/', 'References: ****', $aEmailContent['body']);
|
||||
foreach($aFieldsToCheck as $sCode => $expectedValue) {
|
||||
$this->assertEquals($expectedValue, $aEmailContent[$sCode]);
|
||||
}
|
||||
}
|
||||
|
||||
public function prepareMessageContentProvider()
|
||||
{
|
||||
return [
|
||||
'subject-no-placeholder' => [
|
||||
'EN US',
|
||||
['subject' => 'This is a test'],
|
||||
['subject' => 'This is a test'],
|
||||
],
|
||||
'subject-with-placeholder' => [
|
||||
'EN US',
|
||||
['subject' => 'Ticket "$this->title$" created'],
|
||||
['subject' => 'Ticket "Test UserRequest" created'],
|
||||
],
|
||||
'simple-to-oql' => [
|
||||
'EN US',
|
||||
['to' => "SELECT Person WHERE email='some.valid@email.com'"],
|
||||
['to' => 'some.valid@email.com'],
|
||||
],
|
||||
'simple-to-oql_ignoring_ignore_notify' => [
|
||||
'EN US',
|
||||
['to' => "SELECT Person WHERE email='some.valid2@email.com'"],
|
||||
['to' => 'some.valid2@email.com'], // contact2 has 'notify' set to 'no' BUT by default when don't care
|
||||
],
|
||||
'simple-to-oql-not-bypassing-notify' => [
|
||||
'EN US',
|
||||
['to' => "SELECT Person WHERE email='some.valid2@email.com'", 'ignore_notify' => 'no'],
|
||||
['to' => ''], // contact2 has 'notify' set to 'no'
|
||||
],
|
||||
'subject-with-localized-placeholder (default behavior)' => [
|
||||
'EN US',
|
||||
['subject' => 'Ticket in state "$this->label(status)$" created'],
|
||||
['subject' => 'Ticket in state "New" created'],
|
||||
],
|
||||
'subject-with-localized-placeholder (default behavior 2)' => [
|
||||
'FR FR',
|
||||
['subject' => 'Ticket in state "$this->label(status)$" created'],
|
||||
['subject' => 'Ticket in state "Nouveau" created'],
|
||||
],
|
||||
'subject-with-localized-placeholder (new behavior)' => [
|
||||
'FR FR',
|
||||
['subject' => 'Ticket in state "$this->label(status)$" created', 'language' => 'EN US'],
|
||||
['subject' => 'Ticket in state "New" created'],
|
||||
],
|
||||
'simple-body-with-placeholder' => [
|
||||
'EN US',
|
||||
['body' => '<p>Ticket "$this->title$" created.</p>'],
|
||||
['body' => '<p>Ticket "Test UserRequest" created.</p>'],
|
||||
],
|
||||
'simple-body-with-placeholder-TEST-mode' => [
|
||||
'EN US',
|
||||
['body' => '<p>Ticket "$this->title$" created.</p>', 'status' => 'test'],
|
||||
['body' =>
|
||||
<<<HTML
|
||||
<p>Ticket "Test UserRequest" created.</p><div style="border: dashed;">
|
||||
<h1>Testing email notification <span class="object-ref " title="****"><a class="object-ref-link" href="****">Test action</a></span></h1>
|
||||
<p>The email should be sent with the following properties
|
||||
<ul>
|
||||
<li>TO: </li>
|
||||
<li>CC: </li>
|
||||
<li>BCC: </li>
|
||||
<li>From: unit-test@openitop.org</li>
|
||||
<li>Reply-To: </li>
|
||||
<li>References: ****</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
HTML
|
||||
,
|
||||
'subject' => 'TEST[Test subject]',
|
||||
],
|
||||
],
|
||||
'more-complex-body-and-title-with-placeholder' => [
|
||||
'EN US',
|
||||
['subject' => 'Ticket "$this->title$" created'],
|
||||
['subject' => 'Ticket "Test UserRequest" created'],
|
||||
['body' => '<h1>Ticket "$this->title$" created.</h1><p>Description: $this->html(description)</p>'],
|
||||
['body' => '<h1>Ticket "Test UserRequest" created.</h1><p>Description: <p>Multi-line<br/>description</p></p>'],
|
||||
],
|
||||
'simple-body-with-placeholder_and_template' => [
|
||||
'EN US',
|
||||
['body' => '<p>Ticket "$this->title$" created.</p>', 'html_template' => true],
|
||||
['body' =>
|
||||
<<<HTML
|
||||
<body>
|
||||
<table data-something-that-would-be-removed-by-the-sanitizer-through-ckeditor-but-that-will-stay-with-the-template="bar">
|
||||
<tr><td>Formatted eMail</td></tr>
|
||||
<tr><td><p>Ticket "Test UserRequest" created.</p></td></tr>
|
||||
</body>
|
||||
HTML
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider doCheckToWriteProvider
|
||||
* @param string $sBody
|
||||
* @param string $sHtmlTemplate
|
||||
* @param string[] $aExpectedWarnings
|
||||
*/
|
||||
public function testDoCheckToWrite(string $sBody, ?string $sHtmlTemplate, $expectedWarnings)
|
||||
{
|
||||
$oActionEmail = new ActionEmail();
|
||||
// Set mandatory fields
|
||||
$oActionEmail->Set('name', 'test');
|
||||
$oActionEmail->Set('subject', 'Ga Bu Zo Meu');
|
||||
// Set the fields for testing
|
||||
$oActionEmail->Set('body', $sBody);
|
||||
if ($sHtmlTemplate !== null) {
|
||||
$oDoc = new \ormDocument($sHtmlTemplate, 'text/html', 'template.html');
|
||||
$oActionEmail->Set('html_template', $oDoc);
|
||||
}
|
||||
$oActionEmail->DoCheckToWrite();
|
||||
$aWarnings = $this->GetNonPublicProperty($oActionEmail, 'm_aCheckWarnings');
|
||||
if ($expectedWarnings === null) {
|
||||
$this->assertEquals($aWarnings, $expectedWarnings);
|
||||
} else {
|
||||
// The warning messages are localized, but the provider functions does not
|
||||
// have access to the Dict class, so let's replace the value given by the
|
||||
// provider by a statically precomputed and localized message
|
||||
foreach($expectedWarnings as $index => $sMessageKey) {
|
||||
$expectedWarnings[$index] = static::$aWarningMessages[$sMessageKey];
|
||||
}
|
||||
$this->assertEquals($aWarnings, $expectedWarnings);
|
||||
}
|
||||
}
|
||||
|
||||
public function doCheckToWriteProvider()
|
||||
{
|
||||
return [
|
||||
'no warnings' => [
|
||||
'<p>Some text here</p>',
|
||||
'<div>$content$</div>',
|
||||
null
|
||||
],
|
||||
'$content$ missing' => [
|
||||
'<p>Some text here</p>',
|
||||
'<div>no placeholder</div>',
|
||||
[ 'warning-missing-content' ]
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user