237 lines
7 KiB
PHP
237 lines
7 KiB
PHP
<?php /** @noinspection SpellCheckingInspection */
|
|
|
|
namespace Civi\Mailinglistsync;
|
|
|
|
use CRM_Mailinglistsync_ExtensionUtil as E;
|
|
use Civi\Mailinglistsync\Exceptions\MailinglistException;
|
|
|
|
class ADGroupMailingList extends GroupMailingList {
|
|
|
|
public const LOCATION_TYPE = 'AD_Mailing_List_Address';
|
|
|
|
protected string $sid;
|
|
|
|
/**
|
|
* Get an AD mailing list by its SID.
|
|
*
|
|
* @params string $sid
|
|
* @param string $sid
|
|
*
|
|
* @return \Civi\Mailinglistsync\ADGroupMailingList|null
|
|
*
|
|
* @throws \CRM_Core_Exception
|
|
* @throws \Civi\API\Exception\UnauthorizedException
|
|
* @throws \Civi\Mailinglistsync\Exceptions\MailinglistException
|
|
*/
|
|
public static function getBySID(string $sid): ?self {
|
|
$id = static::RELATED_CLASS::get()
|
|
->addSelect('id')
|
|
->addWhere(static::CUSTOM_GROUP_NAME . '.Active_Directory_SID', '=', $sid)
|
|
->execute()
|
|
->first()['id'];
|
|
|
|
$groups = \CRM_Contact_BAO_Group::getGroups(['id' => $id]);
|
|
$groupId = array_pop($groups);
|
|
return $groupId ? new self($groupId) : NULL;
|
|
}
|
|
|
|
/**
|
|
* Synchronize recipients with a list of SIDs and e-mail addresses.
|
|
*
|
|
* @param array $recipients
|
|
*
|
|
* @return array A description of the changes made
|
|
*
|
|
* @throws \Civi\Mailinglistsync\Exceptions\MailinglistException
|
|
*/
|
|
public function syncRecipients(array $recipients): array {
|
|
|
|
$adGroupMembers = $this->getRecipients();
|
|
|
|
// Add new recipients
|
|
$recipientsAdded = [];
|
|
foreach ($recipients as $recipient) {
|
|
if (empty($adGroupMembers[$recipient['sid']] ?? NULL)) {
|
|
$recipientsAdded[$recipient['sid']] = $this->addRecipient($recipient);
|
|
}
|
|
}
|
|
|
|
// Remove recipients that are no longer in the list
|
|
$recipientsRemoved = [];
|
|
foreach ($adGroupMembers as $adGroupMember) {
|
|
/* @var \Civi\Mailinglistsync\MailingListRecipient $adGroupMember */
|
|
if (!in_array($adGroupMember->getSid(), array_column($recipients, 'sid'))) {
|
|
$recipientsRemoved[$adGroupMember->getSid()] = $this->removeRecipient($adGroupMember);
|
|
}
|
|
}
|
|
|
|
// Update recipients
|
|
$recipientsUpdated = [];
|
|
|
|
$recipientAttributesMap = [
|
|
// Map recipient attribute names to method names (get/set)
|
|
'first_name' => 'FirstName',
|
|
'last_name' => 'LastName',
|
|
'email' => 'Email',
|
|
];
|
|
|
|
foreach ($recipients as $recipient) {
|
|
$changed = FALSE;
|
|
|
|
// Find the group member by SID
|
|
$adGroupMemberArray = array_filter(
|
|
$adGroupMembers,
|
|
fn($adGroupMember) => $adGroupMember->getSid() === $recipient['sid']
|
|
);
|
|
$count = count($adGroupMemberArray);
|
|
if ($count === 0) {
|
|
continue;
|
|
}
|
|
elseif ($count > 1) {
|
|
throw new MailinglistException(
|
|
"Multiple recipients with the same SID",
|
|
MailinglistException::ERROR_CODE_MULTIPLE_RECIPIENTS
|
|
);
|
|
}
|
|
/* @var \Civi\Mailinglistsync\MailingListRecipient $adGroupMember */
|
|
$adGroupMember = array_pop($adGroupMemberArray);
|
|
|
|
// Update attributes if they have changed
|
|
foreach ($recipientAttributesMap as $attrName => $methodName) {
|
|
$changed = self::updateRecipient(
|
|
$adGroupMember,
|
|
$recipient,
|
|
$attrName,
|
|
fn() => $adGroupMember->{"get$methodName"}(),
|
|
fn($value) => $adGroupMember->{"set$methodName"}($value),
|
|
$recipientsUpdated,
|
|
) || $changed;
|
|
}
|
|
|
|
// Apply changes
|
|
if ($changed) {
|
|
$adGroupMember->save();
|
|
}
|
|
}
|
|
|
|
// Count errors
|
|
$errorCount = count(array_filter(
|
|
$recipientsAdded,
|
|
fn($recipient) => $recipient['is_error']
|
|
));
|
|
$errorCount += count(array_filter(
|
|
$recipientsRemoved,
|
|
fn($recipient) => $recipient['is_error']
|
|
));
|
|
$errorCount += count(array_filter(
|
|
$recipientsUpdated,
|
|
fn($recipient) => array_filter($recipient, fn($attr) => $attr['is_error'])
|
|
));
|
|
|
|
return [
|
|
'error_count' => $errorCount,
|
|
'recipients_added' => $recipientsAdded,
|
|
'recipients_removed' => $recipientsRemoved,
|
|
'recipients_updated' => $recipientsUpdated,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get a list of recipients indexed by SID.
|
|
*
|
|
* @override GroupMailingList::getRecipients()
|
|
* @return array
|
|
* @throws \Civi\Mailinglistsync\Exceptions\MailinglistException
|
|
*/
|
|
public function getRecipients(): array {
|
|
$recipients = parent::getRecipients();
|
|
return array_column($recipients, null, fn($recipient) => $recipient->getSid());
|
|
}
|
|
|
|
private function addRecipient(array $recipient): array {
|
|
$result = ['recipient' => $recipient];
|
|
|
|
try {
|
|
// Try to find an existing contact
|
|
$contactSearch = $this->findExistingContact(
|
|
firstName: $recipient['first_name'],
|
|
lastName: $recipient['last_name'],
|
|
email: $recipient['email'],
|
|
);
|
|
if ($contactSearch !== NULL) {
|
|
$result['is_error'] = FALSE;
|
|
$result['recipient']['contact_id'] = $contactSearch['contact']['id'];
|
|
$result['recipient']['found_by'] = $contactSearch['found_by'];
|
|
$result['recipient']['contact_created'] = FALSE;
|
|
return $result;
|
|
}
|
|
|
|
// Create a new contact if none was found
|
|
$newRecipient = MailingListRecipient::createContact(
|
|
firstName: $recipient['first_name'],
|
|
lastName: $recipient['last_name'],
|
|
email: $recipient['email'],
|
|
sid: $recipient['sid'],
|
|
);
|
|
$result['is_error'] = FALSE;
|
|
$result['recipient']['contact_id'] = $newRecipient->getContactId();
|
|
$result['recipient']['contact_created'] = TRUE;
|
|
return $result;
|
|
}
|
|
catch (MailinglistException $e) {
|
|
$error = $e->getLogMessage();
|
|
\Civi::log(E::LONG_NAME)->error($error);
|
|
$result['is_error'] = TRUE;
|
|
$result['error_message'] = $error;
|
|
$result['recipient']['contact_created'] = FALSE;
|
|
return $result;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper function to update recipient data dynamically.
|
|
* OMG, is this DRY!
|
|
*
|
|
* @param \Civi\Mailinglistsync\MailingListRecipient $old
|
|
* @param array $new
|
|
* @param string $attributeName
|
|
* @param callable $getter
|
|
* @param callable $setter
|
|
* @param array $changes
|
|
*
|
|
* @return bool TRUE if the recipient was updated, FALSE otherwise
|
|
*/
|
|
private static function updateRecipient(
|
|
MailingListRecipient $old,
|
|
array $new,
|
|
string $attributeName,
|
|
callable $getter,
|
|
callable $setter,
|
|
array &$changes,
|
|
): bool {
|
|
$updated = FALSE;
|
|
if ($new[$attributeName] !== $getter()) {
|
|
$error = NULL;
|
|
$oldValue = $getter();
|
|
try {
|
|
$setter($new[$attributeName]);
|
|
$updated = TRUE;
|
|
}
|
|
catch (MailinglistException $e) {
|
|
\Civi::log(E::LONG_NAME)->error($e->getLogMessage());
|
|
$error = $e->getLogMessage();
|
|
}
|
|
finally {
|
|
$changes[$old['sid']][$attributeName] = [
|
|
'is_error' => $error !== NULL,
|
|
'old' => $oldValue,
|
|
'new' => $new[$attributeName],
|
|
];
|
|
if ($error !== NULL) {
|
|
$changes[$old['sid']][$attributeName]['error'] = $error;
|
|
}
|
|
}
|
|
}
|
|
return $updated;
|
|
}
|
|
}
|