🔖 Version 1.0.0-beta

This commit is contained in:
Marc Koch 2025-03-20 16:01:05 +01:00
parent c93a06972b
commit 460a811554
Signed by: marc.koch
GPG key ID: 12406554CFB028B9
26 changed files with 2480 additions and 771 deletions

View file

@ -9,7 +9,6 @@ use Civi\Mailinglistsync\Exceptions\MailinglistException;
use CRM_Mailinglistsync_ExtensionUtil as E;
use Civi\Mailinglistsync\EventMailingList;
use Civi\Mailinglistsync\GroupMailingList;
use Civi\Mailinglistsync\ADGroupMailingList;
use function Civi\Mailinglistsync\getLocationTypes;
require_once 'Civi/Mailinglistsync/Utils.php';
@ -49,27 +48,152 @@ function mailinglistsync_civicrm_enable(): void {
*/
function mailinglistsync_civicrm_validateForm($formName, &$fields, &$files, &$form, &$errors): void {
// Validate custom fields in group and event forms.
if ($formName == 'CRM_Group_Form_Edit') {
$mailingList = new GroupMailingList();
if ($formName === 'CRM_Group_Form_Edit') {
if ($_REQUEST['action'] === 'delete' || $_REQUEST['action'] === 'update') {
$mailingList = new GroupMailingList(intval($_REQUEST['id']));
}
else {
$mailingList = new GroupMailingList();
}
}
elseif ($formName == 'CRM_Event_Form_ManageEvent_EventInfo') {
$mailingList = new EventMailingList();
elseif ($formName === 'CRM_Event_Form_ManageEvent_EventInfo') {
if ($_REQUEST['action'] === 'delete' || $_REQUEST['action'] === 'update') {
$mailingList = new EventMailingList(intval($_REQUEST['id']));
}
else {
$mailingList = new EventMailingList();
}
}
if (!empty($mailingList)) {
// We cannot delete the corresponding mlmmj mailing list in the post hook
// so we have to deal with it here
if ($_REQUEST['action'] === 'delete' && $mailingList->isEnabled()) {
try {
$mailingList->delete();
}
catch (MailinglistException $e) {
$errorCode = $e->getCode();
if ($errorCode !== MailinglistException::ERROR_CODE_DELETE_EMAIL_ADDRESS_FAILED) {
\Civi::log(E::LONG_NAME)->error($e->getMessage());
}
CRM_Core_Session::setStatus(
E::ts('Failed to delete mlmmj mailing list: %1', [1 => $e->getMessage()]),
E::ts('Deletion failed'),
'alert',
);
}
}
// Handle group and event mailing list updates which affect the mlmmj mailing list
if ($_REQUEST['action'] === 'update' && $mailingList->isEnabled()) {
$customFields = $mailingList::translateCustomFields($fields);
// If enabled changes from TRUE to FALSE, delete the mlmmj mailing list
if ($customFields['Enable_mailing_list']['value'] === "0") {
try {
$mailingList->delete();
}
catch (MailinglistException $e) {
$errorCode = $e->getCode();
if ($errorCode !== MailinglistException::ERROR_CODE_DELETE_EMAIL_ADDRESS_FAILED) {
\Civi::log(E::LONG_NAME)->error($e->getMessage());
}
CRM_Core_Session::setStatus(
E::ts('Failed to delete mlmmj mailing list: %1', [1 => $e->getMessage()]),
E::ts('Deletion failed'),
'alert',
);
}
}
// If email address has changed, delete and mark group for creation
elseif ($customFields['E_mail_address']['value'] !== $mailingList->getEmailAddress()) {
try {
$mailingList->delete();
}
catch (MailinglistException $e) {
$errorCode = $e->getCode();
if ($errorCode !== MailinglistException::ERROR_CODE_DELETE_EMAIL_ADDRESS_FAILED) {
\Civi::log(E::LONG_NAME)->error($e->getMessage());
}
CRM_Core_Session::setStatus(
E::ts('Failed to delete mlmmj mailing list: %1', [1 => $e->getMessage()]),
E::ts('Deletion failed'),
'alert',
);
}
// Queue mailinglist for synchronization with mlmmj
if ($mailingList::class === GroupMailingList::class) {
$queue = \Civi::queue('propeace-mailinglist-group-queue', [
'type' => 'SqlParallel',
'is_autorun' => FALSE,
'reset' => FALSE,
'error' => 'drop',
]);
$queue->createItem(new CRM_Queue_Task(
// callback
['Civi\Mailinglistsync\QueueHelper', 'storeInstance'],
// arguments
[$mailingList->getId(), $mailingList::class],
// title
"Sync Group ID '{$mailingList->getId()}'"
));
}
elseif ($mailingList::class === EventMailingList::class) {
$queue = \Civi::queue('propeace-mailinglist-event-queue', [
'type' => 'SqlParallel',
'is_autorun' => FALSE,
'reset' => FALSE,
'error' => 'drop',
]);
$queue->createItem(new CRM_Queue_Task(
// callback
['Civi\Mailinglistsync\QueueHelper', 'storeInstance'],
// arguments
[$mailingList->getId(), $mailingList::class],
// title
"Sync Event ID '{$mailingList->getId()}'"
));
}
}
}
// Validate custom fields
$mailingList::validateCustomFields($fields, $form, $errors);
}
// Check permission to alter group membership via form
if ($formName == 'CRM_Contact_Form_GroupContact' || $formName == 'CRM_Contact_Form_Task_AddToGroup') {
if ($formName === 'CRM_Contact_Form_GroupContact' || $formName === 'CRM_Contact_Form_Task_AddToGroup') {
$mailingList = new GroupMailingList($fields['group_id']);
_check_group_membership_permissions($mailingList, $errors);
_mailinglistsync_check_group_membership_permissions($mailingList, $errors);
}
elseif ($formName == 'CRM_Event_Form_Participant') {
elseif ($formName === 'CRM_Event_Form_Participant') {
$mailingList = new EventMailingList($fields['event_id']);
_mailinglistsync_check_event_membership_permissions($mailingList, $errors);
}
}
function mailinglistsync_civicrm_pre($op, $objectName, $objectId, &$params) {
if ($op === 'delete' || $op === 'edit') {
if ($objectName === 'Group' || $objectName === 'Event') {
$mailingList = $objectName === 'Group'
? new GroupMailingList($objectId)
: new EventMailingList($objectId);
if ($mailingList->isEnabled()) {
// If email has changed, delete the mailing list and create a new one
if ($mailingList->getEmailAddress() !== $params['email']) {
//
}
}
}
}
}
/**
* Implements hook_civicrm_post() to check on permissions to alter mailing list
* groups and sync group with mlmmj.
@ -79,14 +203,14 @@ function mailinglistsync_civicrm_validateForm($formName, &$fields, &$files, &$fo
* @throws \CRM_Core_Exception
*/
function mailinglistsync_civicrm_post(string $op, string $objectName, int $objectId, &$objectRef) {
if ($op == 'delete' || $op == 'edit' || $op == 'create') {
if ($op === 'delete' || $op === 'edit' || $op === 'create') {
// Check on groups mailing list
// Note: I wonder why $objectId refers to the group instead of the group contact here.
if ($objectName == 'GroupContact') {
$mailingList = new GroupMailingList($objectId);
if ($objectName === 'GroupContact') {
$mailingList = new GroupMailingList($objectRef->group_id ?? $objectId);
// Check permission to alter group membership
if ($mailingList->isMailingList() && !CRM_Core_Permission::check('manage_group_mailinglists')) {
if ($mailingList->isEnabled() && !CRM_Core_Permission::check('manage_group_mailinglists')) {
CRM_Core_Session::setStatus(
E::ts('You do not have permission to manage memberships of mailing list groups.'),
E::ts('Permission Denied'),
@ -113,7 +237,7 @@ function mailinglistsync_civicrm_post(string $op, string $objectName, int $objec
}
// Check on event mailing lists
elseif ($objectName == 'Participant') {
elseif ($objectName === 'Participant') {
$eventId = $objectRef->event_id ?? Event::get()
->addSelect('event_id')
->addWhere('id', '=', $objectId)
@ -122,7 +246,7 @@ function mailinglistsync_civicrm_post(string $op, string $objectName, int $objec
$mailingList = new GroupMailingList($eventId);
// Check permission to alter event mailing list
if ($mailingList->isMailingList() && !CRM_Core_Permission::check('manage_event_mailinglists')) {
if ($mailingList->isEnabled() && !CRM_Core_Permission::check('manage_event_mailinglists')) {
CRM_Core_Session::setStatus(
E::ts('You do not have permission to manage event mailing lists.'),
E::ts('Permission Denied'),
@ -135,18 +259,8 @@ function mailinglistsync_civicrm_post(string $op, string $objectName, int $objec
}
}
// Delete mlmmj mailing list
if (
$op == 'delete' &&
!empty($mailingList) &&
($mailingList->isMailingList() || $mailingList->isADGroup())
) {
$mailingList->deleteMailingList(); // TODO
}
// If this is an e-mail address of a location type used for mailing lists
if ($objectName == 'Email' && in_array((int) $objectRef->location_type_id, array_keys(getLocationTypes()))) {
if ($objectName === 'Email' && in_array((int) $objectRef->location_type_id, array_keys(getLocationTypes()))) {
// Ensure that only one e-mail address of this location type is set for this contact
$result = Email::get()
->addSelect('contact_id', 'contact.display_name')
@ -160,7 +274,7 @@ function mailinglistsync_civicrm_post(string $op, string $objectName, int $objec
if (!empty($result) && $op != 'delete') {
throw new MailinglistException(
E::ts("An e-mail address of a mailing list type is already used for this contact"),
"An e-mail address of a mailing list type is already used for this contact",
MailinglistException::ERROR_CODE_UPDATE_EMAIL_ADDRESS_FAILED
);
}
@ -168,7 +282,11 @@ function mailinglistsync_civicrm_post(string $op, string $objectName, int $objec
// Ensure that this email address is only used for one contact
$results = Email::get()
->addSelect('contact.id', 'contact.display_name')
->addJoin('Contact AS contact', 'LEFT', ['contact_id', '=', 'contact.id'])
->addJoin('Contact AS contact', 'LEFT', [
'contact_id',
'=',
'contact.id',
])
->addWhere('contact_id', '!=', $objectRef->contact_id)
->addWhere('email', '=', $objectRef->email)
->addWhere('location_type_id', '=', $objectRef->location_type_id)
@ -176,7 +294,6 @@ function mailinglistsync_civicrm_post(string $op, string $objectName, int $objec
->getArrayCopy();
if (!empty($results) && $op != 'delete') {
// Delete e-mail address if it is not allowed
// TODO: This is a workaround. We should prevent the creation of the e-mail address in the first place.
_mailinglistsync_delete_email_address((int) $objectRef->id);
@ -219,9 +336,9 @@ function mailinglistsync_civicrm_post(string $op, string $objectName, int $objec
function mailinglistsync_civicrm_postCommit(string $op, string $objectName, int $objectId, &$objectRef) {
// Sync groups mailing list
// Note: I wonder why $objectId refers to the group instead of the group contact here.
if ($objectName == 'GroupContact') {
$mailingList = new GroupMailingList($objectId);
if ($mailingList->isMailingList() || $mailingList->isADGroup()) {
if ($objectName === 'GroupContact') {
$mailingList = new GroupMailingList($objectRef->group_id ?? $objectId);
if ($mailingList->isEnabled()) {
// Queue group for synchronization with mlmmj
$queue = \Civi::queue('propeace-mailinglist-group-queue', [
'type' => 'SqlParallel',
@ -235,20 +352,41 @@ function mailinglistsync_civicrm_postCommit(string $op, string $objectName, int
// arguments
[$mailingList->getId(), $mailingList::class],
// title
"Sync Group ID '$objectId'"
"Sync Group ID '{$mailingList->getId()}'"
));
}
}
elseif ($objectName === 'Group') {
$mailingList = new GroupMailingList($objectId);
if ($mailingList->isEnabled()) {
// Queue group for synchronization with mlmmj
$queue = \Civi::queue('propeace-mailinglist-group-queue', [
'type' => 'SqlParallel',
'is_autorun' => FALSE,
'reset' => FALSE,
'error' => 'drop',
]);
$queue->createItem(new CRM_Queue_Task(
// callback
['Civi\Mailinglistsync\QueueHelper', 'storeInstance'],
// arguments
[$mailingList->getId(), $mailingList::class],
// title
"Sync Group ID '{$mailingList->getId()}'"
));
}
}
// Sync event mailing lists
elseif ($objectName == 'Participant') {
elseif ($objectName === 'Participant') {
$eventId = $objectRef->event_id ?? Participant::get()
->addSelect('event_id')
->addWhere('id', '=', $objectId)
->execute()
->first()['event_id'];
$mailingList = new EventMailingList($eventId);
if ($mailingList->isMailingList()) {
if ($mailingList->isEnabled()) {
// Queue event for synchronization with mlmmj
$queue = \Civi::queue('propeace-mailinglist-event-queue', [
'type' => 'SqlParallel',
@ -262,43 +400,86 @@ function mailinglistsync_civicrm_postCommit(string $op, string $objectName, int
// arguments
[$mailingList->getId(), $mailingList::class],
// title
"Sync Event ID '$objectId'"
"Sync Event ID '{$mailingList->getId()}'"
));
}
}
elseif ($objectName === 'Event') {
$mailingList = new EventMailingList($objectId);
if ($mailingList->isEnabled()) {
// Queue event for synchronization with mlmmj
$queue = \Civi::queue('propeace-mailinglist-event-queue', [
'type' => 'SqlParallel',
'is_autorun' => FALSE,
'reset' => FALSE,
'error' => 'drop',
]);
$queue->createItem(new CRM_Queue_Task(
// callback
['Civi\Mailinglistsync\QueueHelper', 'storeInstance'],
// arguments
[$mailingList->getId(), $mailingList::class],
// title
"Sync Event ID '{$mailingList->getId()}'"
));
}
}
if ($objectName === 'GroupContact') {
$mailingList = new GroupMailingList($objectRef->group_id ?? $objectId);
if ($mailingList->isEnabled()) {
// Queue group for synchronization with mlmmj
$queue = \Civi::queue('propeace-mailinglist-group-queue', [
'type' => 'SqlParallel',
'is_autorun' => FALSE,
'reset' => FALSE,
'error' => 'drop',
]);
$queue->createItem(new CRM_Queue_Task(
// callback
['Civi\Mailinglistsync\QueueHelper', 'storeInstance'],
// arguments
[$mailingList->getId(), $mailingList::class],
// title
"Sync Group ID '{$mailingList->getId()}'"
));
}
}
// Sync e-mail addresses
elseif ($objectName == 'Email' && in_array((int) $objectRef->location_type_id, array_keys(getLocationTypes()))) {
// Only sync e-mail addresses of mailing list types
$locationType = \Civi\Api4\LocationType::get()
->addSelect('name')
->addWhere('id', '=', $objectRef->location_type_id)
->execute()
->first()['name'];
if (!in_array($locationType, [
GroupMailingList::LOCATION_TYPE,
ADGroupMailingList::LOCATION_TYPE,
EventMailingList::LOCATION_TYPE,
])) {
return;
elseif ($objectName === 'Email') {
// If an email address update comes from an api call, the
// objectRef->location_type_id is not set. So we have to get it from the
// database.
if (empty($objectRef->location_type_id)) {
$locationTypeId = \Civi\Api4\Email::get()
->addSelect('location_type_id')
->addWhere('id', '=', $objectRef->id)
->addWhere('location_type_id', 'IN', array_keys(getLocationTypes()))
->execute()
->first()['location_type_id'];
}
if (
!empty($locationTypeId) ||
in_array((int) $objectRef->location_type_id, array_keys(getLocationTypes()))
) {
// Queue email address for synchronization with mlmmj
$queue = \Civi::queue('propeace-mailinglist-email-queue', [
'type' => 'SqlParallel',
'is_autorun' => FALSE,
'reset' => FALSE,
'error' => 'drop',
]);
$queue->createItem(new CRM_Queue_Task(
// callback
['Civi\Mailinglistsync\QueueHelper', 'storeEmail'],
// arguments
[$objectRef->email],
// title
"Sync E-Mail '$objectRef->email'"
));
}
// Queue email address for synchronization with mlmmj
$queue = \Civi::queue('propeace-mailinglist-email-queue', [
'type' => 'SqlParallel',
'is_autorun' => FALSE,
'reset' => FALSE,
'error' => 'drop',
]);
$queue->createItem(new CRM_Queue_Task(
// callback
['Civi\Mailinglistsync\QueueHelper', 'addToEmails'],
// arguments
[$objectRef->email],
// title
"Sync E-Mail '$objectRef->email'"
));
}
}
@ -330,6 +511,23 @@ function mailinglistsync_civicrm_permission(&$permissions) {
];
}
/**
* Check permissions to alter group membership.
*
* @param \Civi\Mailinglistsync\GroupMailingList $mailingList
* @param $errors
*
* @return void
*/
function _mailinglistsync_check_group_membership_permissions(GroupMailingList $mailingList, &$errors): void {
if ($mailingList->isEnabled() && !CRM_Core_Permission::check('manage_group_mailinglists')) {
$errors['group_id'] = E::ts('You do not have permission to manage group membership.');
}
if ($mailingList->isADGroup() && !CRM_Core_Permission::check('manage_ad_mailinglists')) {
$errors['group_id'] = E::ts('You do not have permission to manage AD group membership.');
}
}
/**
* Check permissions to alter event membership.
*
@ -339,7 +537,7 @@ function mailinglistsync_civicrm_permission(&$permissions) {
* @return void
*/
function _mailinglistsync_check_event_membership_permissions(EventMailingList $mailingList, &$errors): void {
if ($mailingList->isMailingList() && !CRM_Core_Permission::check('manage_event_mailinglists')) {
if ($mailingList->isEnabled() && !CRM_Core_Permission::check('manage_event_mailinglists')) {
$errors['event_id'] = E::ts('You do not have permission to manage event membership.');
}
}
@ -361,7 +559,7 @@ function _mailinglistsync_delete_email_address(int $emailId): void {
}
catch (\Exception $e) {
throw new MailinglistException(
E::ts('Failed to delete e-mail address'),
"Failed to delete e-mail address: {$e}",
MailinglistException::ERROR_CODE_DELETE_EMAIL_ADDRESS_FAILED
);
}