Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions config/default.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@
],
'password' => [
'create' => filter_var(env('PASSBOLT_EMAIL_SEND_PASSWORD_CREATE', false), FILTER_VALIDATE_BOOLEAN),
'updateSelf' => filter_var(env('PASSBOLT_EMAIL_SEND_PASSWORD_UPDATE_SELF', true), FILTER_VALIDATE_BOOLEAN),
'deleteSelf' => filter_var(env('PASSBOLT_EMAIL_SEND_PASSWORD_DELETE_SELF', false), FILTER_VALIDATE_BOOLEAN),
'share' => filter_var(env('PASSBOLT_EMAIL_SEND_PASSWORD_SHARE', true), FILTER_VALIDATE_BOOLEAN),
'update' => filter_var(env('PASSBOLT_EMAIL_SEND_PASSWORD_UPDATE', true), FILTER_VALIDATE_BOOLEAN),
'delete' => filter_var(env('PASSBOLT_EMAIL_SEND_PASSWORD_DELETE', true), FILTER_VALIDATE_BOOLEAN),
Expand Down Expand Up @@ -166,6 +168,8 @@
],
'folder' => [
'create' => filter_var(env('PASSBOLT_EMAIL_SEND_FOLDER_CREATE', false), FILTER_VALIDATE_BOOLEAN),
'updateSelf' => filter_var(env('PASSBOLT_EMAIL_SEND_FOLDER_UPDATE_SELF', true), FILTER_VALIDATE_BOOLEAN),
'deleteSelf' => filter_var(env('PASSBOLT_EMAIL_SEND_FOLDER_DELETE_SELF', false), FILTER_VALIDATE_BOOLEAN),
'update' => filter_var(env('PASSBOLT_EMAIL_SEND_FOLDER_UPDATE', true), FILTER_VALIDATE_BOOLEAN),
'delete' => filter_var(env('PASSBOLT_EMAIL_SEND_FOLDER_DELETE', true), FILTER_VALIDATE_BOOLEAN),
'share' => filter_var(env('PASSBOLT_EMAIL_SEND_FOLDER_SHARE', true), FILTER_VALIDATE_BOOLEAN),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ public function testNotificationOrgSettingsGetControllerSuccessDBOverride()
$cases = [
'send_comment_add' => false,
'send_password_create' => true,
'send_password_updateSelf' => false,
'send_password_deleteSelf' => true,
'send_password_share' => false,
];

Expand Down Expand Up @@ -125,6 +127,8 @@ public function testNotificationOrgSettingsGetControllerSuccessFileOverride()
$cases = [
'send_comment_add' => false,
'send_password_create' => true,
'send_password_updateSelf' => false,
'send_password_deleteSelf' => true,
'send_password_share' => false,
];

Expand Down Expand Up @@ -154,6 +158,8 @@ public function testNotificationOrgSettingsGetControllerSuccessBothOverride()
$cases = [
'send_comment_add' => false,
'send_password_create' => true,
'send_password_updateSelf' => false,
'send_password_deleteSelf' => true,
'send_password_share' => false,
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ public function testNotificationOrgSettingsPostControllerSuccess()
'show_username' => false,
'send_comment_add' => false,
'send_password_create' => false,
'send_password_updateSelf' => false,
'send_password_deleteSelf' => false,
'send_password_share' => false,
'send_password_update' => false,
'send_password_delete' => false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
use Cake\ORM\Query\SelectQuery;
use Cake\ORM\TableRegistry;
use InvalidArgumentException;
use Passbolt\EmailNotificationSettings\Utility\EmailNotificationSettings;
use Passbolt\Folders\Model\Entity\Folder;
use Passbolt\Folders\Service\Folders\FoldersDeleteService;
use Passbolt\Locale\Service\LocaleService;
Expand Down Expand Up @@ -96,9 +97,14 @@ public function onSubscribedEvent(Event $event): EmailCollection
}

$operator = $this->usersTable->findFirstForEmail($uac->getId());
$sendDeleteSelfEmail = EmailNotificationSettings::get('send.folder.deleteSelf');
/** @var array<\App\Model\Entity\User> $recipients */
$recipients = $this->findUsersUsernameToSendEmailTo($users);
foreach ($recipients as $recipient) {
if ($recipient->id === $operator->id && !$sendDeleteSelfEmail) {
continue;
}

$email = $this->createEmail($recipient, $operator, $folder);
$emailCollection->addEmail($email);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use Cake\ORM\Query\SelectQuery;
use Cake\ORM\TableRegistry;
use InvalidArgumentException;
use Passbolt\EmailNotificationSettings\Utility\EmailNotificationSettings;
use Passbolt\Folders\Model\Entity\Folder;
use Passbolt\Folders\Service\Folders\FoldersUpdateService;
use Passbolt\Locale\Service\LocaleService;
Expand Down Expand Up @@ -105,9 +106,14 @@ public function onSubscribedEvent(Event $event): EmailCollection
}

$operator = $this->usersTable->findFirstForEmail($uac->getId());
$sendUpdateSelfEmail = EmailNotificationSettings::get('send.folder.updateSelf');
/** @var array<\App\Model\Entity\User> $recipients */
$recipients = $this->findUsersUsernameToSendEmailTo($folder);
foreach ($recipients as $recipient) {
if ($recipient->id === $operator->id && !$sendUpdateSelfEmail) {
continue;
}

$email = $this->createEmail($recipient, $operator, $folder, $isV5);
$emailCollection->addEmail($email);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ public function buildSchema(Schema $schema): Schema
{
return $schema
->addField('send_folder_create', ['type' => 'boolean', 'default' => false])
->addField('send_folder_updateSelf', ['type' => 'boolean', 'default' => true])
->addField('send_folder_deleteSelf', ['type' => 'boolean', 'default' => false])
->addField('send_folder_delete', ['type' => 'boolean', 'default' => true])
->addField('send_folder_update', ['type' => 'boolean', 'default' => true])
->addField('send_folder_share', ['type' => 'boolean', 'default' => true]);
Expand All @@ -46,6 +48,8 @@ public function buildValidator(Validator $validator): Validator
{
return $validator
->boolean('send_folder_create', __('An email notification setting should be a boolean.'))
->boolean('send_folder_updateSelf', __('An email notification setting should be a boolean.'))
->boolean('send_folder_deleteSelf', __('An email notification setting should be a boolean.'))
->boolean('send_folder_delete', __('An email notification setting should be a boolean.'))
->boolean('send_folder_update', __('An email notification setting should be a boolean.'))
->boolean('send_folder_share', __('An email notification setting should be a boolean.'));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class FolderNotificationSettingsDefinitionTest extends TestCase
public const EXPECTED_FIELDS = [
'send_folder_delete',
'send_folder_create',
'send_folder_updateSelf',
'send_folder_deleteSelf',
'send_folder_update',
'send_folder_share',
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
use App\Utility\UuidFactory;
use Cake\Http\Exception\ForbiddenException;
use Cake\Http\Exception\NotFoundException;
use Passbolt\EmailDigest\Test\Factory\EmailQueueFactory;
use Passbolt\EmailNotificationSettings\Test\Lib\EmailNotificationSettingsTestTrait;
use Passbolt\Folders\Model\Entity\FoldersRelation;
use Passbolt\Folders\Service\Folders\FoldersDeleteService;
Expand Down Expand Up @@ -107,6 +108,27 @@ public function testFolderDelete_CommonSuccess2_NotifyUsersAfterDelete()

$this->service->delete($this->makeUac($userA), $folderA->id);

$this->assertEmailQueueCount(1);
$this->assertSame(0, EmailQueueFactory::find()->where(['email' => $userA->username])->all()->count());
$this->assertEmailSubject($userB->username, "{$userA->profile->first_name} deleted the folder A");
$this->assertEmailInBatchContains("{$userA->profile->first_name} deleted a folder", $userB->username);
}

public function testFolderDelete_CommonSuccess2_NotifyOperatorAfterDeleteWhenEnabled()
{
// Ada is OWNER of folder A
// Betty is OWNER of folder A
// The folder delete self notification is enabled
// ---
// A (Ada:O, Betty:O)
[$userA, $userB] = UserFactory::make(2)->persist();
/** @var \Passbolt\Folders\Model\Entity\Folder $folderA */
$folderA = FolderFactory::make(['name' => 'A'])->withPermissionsFor([$userA, $userB])->persist();

$this->setEmailNotificationSetting('send.folder.deleteSelf', true);

$this->service->delete($this->makeUac($userA), $folderA->id);

$this->assertEmailQueueCount(2);
$this->assertEmailSubject($userA->username, 'You deleted the folder A');
$this->assertEmailInBatchContains('You deleted a folder', $userA->username);
Expand Down Expand Up @@ -583,9 +605,9 @@ public function testFolderDelete_CommonSuccess3_NotifyGroupMembersAfterDelete()

$this->service->delete($this->makeUac($userA), $folderA->id);

// All users with access (direct and via group) should be notified
$this->assertEmailQueueCount(3);
$this->assertEmailSubject($userA->username, 'You deleted the folder A');
// All users with access (direct and via group), except the operator, should be notified.
$this->assertEmailQueueCount(2);
$this->assertSame(0, EmailQueueFactory::find()->where(['email' => $userA->username])->all()->count());
$this->assertEmailSubject($userB->username, "{$userA->profile->first_name} deleted the folder A");
$this->assertEmailSubject($userC->username, "{$userA->profile->first_name} deleted the folder A");
}
Expand Down Expand Up @@ -743,7 +765,7 @@ public function testFolderDelete_SharedSuccess8_NoCascadeMoveResourcesToRootForA
$this->assertFolderRelation($resource1->id, FoldersRelation::FOREIGN_MODEL_RESOURCE, $userB->id, null);
}

public function testFolderDelete_CommonSuccess4_NotifyOnlyOperatorForPersonalFolder()
public function testFolderDelete_CommonSuccess4_DoesNotNotifyOperatorForPersonalFolder()
{
// Ada is OWNER of personal folder A (no other users)
// ---
Expand All @@ -755,8 +777,27 @@ public function testFolderDelete_CommonSuccess4_NotifyOnlyOperatorForPersonalFol

$this->service->delete($this->makeUac($userA), $folderA->id);

$this->assertEmailQueueCount(0);
}

public function testFolderDelete_CommonSuccess4_NotifyOperatorForPersonalFolderWhenEnabled()
{
// Ada is OWNER of personal folder A (no other users)
// The folder delete self notification is enabled
// ---
// A (Ada:O)
/** @var \App\Model\Entity\User $userA */
$userA = UserFactory::make()->persist();
/** @var \Passbolt\Folders\Model\Entity\Folder $folderA */
$folderA = FolderFactory::make(['name' => 'A'])->withPermissionsFor([$userA])->persist();

$this->setEmailNotificationSetting('send.folder.deleteSelf', true);

$this->service->delete($this->makeUac($userA), $folderA->id);

$this->assertEmailQueueCount(1);
$this->assertEmailSubject($userA->username, 'You deleted the folder A');
$this->assertEmailInBatchContains('You deleted a folder', $userA->username);
}

public function testFolderDelete_CommonSuccess5_NotificationRespectsEmailSettings()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use Cake\Http\Exception\ForbiddenException;
use Cake\Http\Exception\NotFoundException;
use Cake\ORM\TableRegistry;
use Passbolt\EmailDigest\Test\Factory\EmailQueueFactory;
use Passbolt\EmailNotificationSettings\Test\Lib\EmailNotificationSettingsTestTrait;
use Passbolt\Folders\Service\Folders\FoldersUpdateService;
use Passbolt\Folders\Test\Factory\FolderFactory;
Expand Down Expand Up @@ -96,7 +97,7 @@ public function testUpdateFolderSuccess_UpdateFolderMeta()
$this->assertEquals('new name', $folderBUpdated->get('name'));
}

public function testUpdateFolderSuccess_NotifyUserAfterUpdate()
public function testUpdateFolderSuccess_NotifyUsersAfterUpdate()
{
// Ada is OWNER of folder A
// Betty has READ on folder A
Expand All @@ -119,6 +120,30 @@ public function testUpdateFolderSuccess_NotifyUserAfterUpdate()
$this->assertEmailInBatchContains("{$userA->profile->first_name} edited a folder", $userB->username);
}

public function testUpdateFolderSuccess_DoesNotNotifyOperatorWhenUpdateSelfDisabled()
{
$this->setEmailNotificationSetting('send.folder.updateSelf', false);

// Ada is OWNER of folder A
// Betty has READ on folder A
// ---
// A (Ada:O, Betty:R)
[$userA, $userB] = UserFactory::make(2)->persist();
$folderA = FolderFactory::make()
->withPermissionsFor([$userA])
->withPermissionsFor([$userB], Permission::READ)
->persist();

$name = 'new name';
$dto = MetadataFolderDto::fromArray(['name' => $name]);
$this->service->update($this->makeUac($userA), $folderA->get('id'), $dto);

$this->assertEmailQueueCount(1);
$this->assertSame(0, EmailQueueFactory::find()->where(['email' => $userA->username])->all()->count());
$this->assertEmailSubject($userB->username, "{$userA->profile->first_name} edited the folder $name");
$this->assertEmailInBatchContains("{$userA->profile->first_name} edited a folder", $userB->username);
}

public function testUpdateFolderError_ValidationError()
{
// Ada is OWNER of folder A
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
$subject = $body['subject'];
$user = $body['user'];
$resource = $body['resource'];
$isOperator = $body['isOperator'];

echo $this->element('Email/module/avatar',[
'url' => AvatarHelper::getAvatarUrl($user['profile']['avatar']),
Expand All @@ -32,7 +33,9 @@
])
]);

$text = __('{0} deleted a password.', Purifier::clean($user['profile']['first_name'] . ' ' . $user['profile']['last_name'])) . '<br/>';
$text = $isOperator
? __('You deleted a password.') . '<br/>'
: __('{0} deleted a password.', Purifier::clean($user['profile']['first_name'] . ' ' . $user['profile']['last_name'])) . '<br/>';

echo $this->element('Email/module/text', ['text' => $text]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public function setUp(): void
{
parent::setUp();
$this->setEmailNotificationsSetting('password.create', true);
Configure::write('passbolt.email.send.password.updateSelf', false);
$this->enableFeaturePlugin(ResourceTypesPlugin::class);
RoleFactory::make()->guest()->persist();
// enable event tracking
Expand Down Expand Up @@ -122,8 +123,8 @@ public function testResourcesUpdateController_Success_SharedKey(string $resource
'isV5',
true
);
$this->assertEmailQueueCount(2);
$this->assertEmailIsInQueue(['email' => $user->username, 'subject' => 'You edited a resource']);
$this->assertEmailQueueCount(1);
$this->assertEmailWithRecipientIsInNotQueue($user->username);
$this->assertEmailIsInQueue([
'email' => $userWithPermission->username,
'subject' => $user->profile->first_name . ' edited a resource',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use App\Test\Factory\UserFactory;
use App\Test\Lib\AppIntegrationTestCase;
use App\Test\Lib\Model\EmailQueueTrait;
use Cake\Core\Configure;
use Cake\I18n\Date;
use Cake\I18n\DateTime;
use Passbolt\Folders\Test\Factory\ResourceFactory;
Expand All @@ -37,6 +38,7 @@ public function setUp(): void
parent::setUp();
$this->enableFeaturePlugin(PasswordExpiryPlugin::class);
PasswordExpirySettingFactory::make()->persist();
Configure::write('passbolt.email.send.password.updateSelf', false);
}

public function testPasswordExpiryResourcesUpdateController_Update_Expiry_Date_In_Future(): void
Expand All @@ -59,7 +61,7 @@ public function testPasswordExpiryResourcesUpdateController_Update_Expiry_Date_I

$resourceUpdated = ResourceFactory::get($resourceToUpdate->id);
$this->assertFalse($resourceUpdated->isExpired());
$this->assertEmailQueueCount(1);
$this->assertEmailQueueIsEmpty();
}

public static function isResourceAlreadyExpired(): array
Expand Down Expand Up @@ -105,7 +107,7 @@ public function testPasswordExpiryResourcesUpdateController_Update_Expiry_Date_I
$this->assertTrue($resourceUpdated->isExpired());
// If the resource is already expired, do not notify the owner who is not performing
// the action, that they have expired emails
$expectedEmails = $isResourceAlreadyExpired ? 3 : 4;
$expectedEmails = $isResourceAlreadyExpired ? 2 : 3;
$this->assertEmailQueueCount($expectedEmails);
$emailDataToOwner = [
'email' => $ownerWithAccess->username,
Expand Down
3 changes: 3 additions & 0 deletions resources/locales/cs_CZ/default.po
Original file line number Diff line number Diff line change
Expand Up @@ -1273,6 +1273,9 @@ msgstr "Nastavení send on password shared by mělo být platný boolean."
msgid "The send on password updated setting should be a boolean."
msgstr "Nastavení send on password updated by mělo být platný boolean."

msgid "The send on password update creator setting should be a boolean."
msgstr "Nastavení odesílání tvůrci při aktualizaci hesla musí být boolean."

msgid "The send on password deleted setting should be a boolean."
msgstr "Nastavení send on password deleted by mělo být platný boolean."

Expand Down
3 changes: 3 additions & 0 deletions resources/locales/de_DE/default.po
Original file line number Diff line number Diff line change
Expand Up @@ -1273,6 +1273,9 @@ msgstr "Die Einstellung \"Senden wenn ein Passwort geteilt wird\" sollte ein Boo
msgid "The send on password updated setting should be a boolean."
msgstr "Die Einstellung \"Senden beim Aktualisieren eines Passworts\" sollte ein Boolean sein."

msgid "The send on password update creator setting should be a boolean."
msgstr "Die Einstellung zum Benachrichtigen des Erstellers bei einer Passwortaktualisierung sollte ein Boolean sein."

msgid "The send on password deleted setting should be a boolean."
msgstr "Die Einstellung \"Senden, wenn ein Passwort gelöscht wird\" sollte ein Boolean sein."

Expand Down
3 changes: 3 additions & 0 deletions resources/locales/en_UK/default.po
Original file line number Diff line number Diff line change
Expand Up @@ -1271,6 +1271,9 @@ msgstr ""
msgid "The send on password updated setting should be a boolean."
msgstr ""

msgid "The send on password update creator setting should be a boolean."
msgstr ""

msgid "The send on password deleted setting should be a boolean."
msgstr ""

Expand Down
3 changes: 3 additions & 0 deletions resources/locales/es_ES/default.po
Original file line number Diff line number Diff line change
Expand Up @@ -1273,6 +1273,9 @@ msgstr "La configuración \"enviar al compartir una contraseña\" debe ser un va
msgid "The send on password updated setting should be a boolean."
msgstr "La configuración \"enviar al actualizar la contraseña\" debe ser un valor booleano."

msgid "The send on password update creator setting should be a boolean."
msgstr "La configuración para notificar al creador cuando se actualiza una contraseña debe ser un valor booleano."

msgid "The send on password deleted setting should be a boolean."
msgstr "La configuración \"enviar al borrar una contraseña\" debe ser un valor booleano."

Expand Down
3 changes: 3 additions & 0 deletions resources/locales/fr_FR/default.po
Original file line number Diff line number Diff line change
Expand Up @@ -1273,6 +1273,9 @@ msgstr "Le réglage de l'envoi lorsqu'un mot de passe est partagé doit être un
msgid "The send on password updated setting should be a boolean."
msgstr "Le réglage de l'envoi lorsqu'un mot de passe est partagé doit être un booléen."

msgid "The send on password update creator setting should be a boolean."
msgstr "Le réglage de l’envoi au créateur lorsqu’un mot de passe est mis à jour doit être un booléen."

msgid "The send on password deleted setting should be a boolean."
msgstr "Le réglage de l'envoi lorsqu'un mot de passe est supprimé doit être un booléen."

Expand Down
3 changes: 3 additions & 0 deletions resources/locales/it_IT/default.po
Original file line number Diff line number Diff line change
Expand Up @@ -1273,6 +1273,9 @@ msgstr "L'impostazione \"invia alla condivisione di una password\" deve essere u
msgid "The send on password updated setting should be a boolean."
msgstr "L'impostazione \"invia all'aggiornamento di una password\" deve essere un valore booleano."

msgid "The send on password update creator setting should be a boolean."
msgstr "L’impostazione per avvisare il creatore quando una password viene aggiornata deve essere un valore booleano."

msgid "The send on password deleted setting should be a boolean."
msgstr "L'impostazione \"invia alla cancellazione di una password\" deve essere un valore booleano."

Expand Down
Loading