🎉 initial commit
This commit is contained in:
commit
c93a06972b
27 changed files with 4189 additions and 0 deletions
237
Civi/Mailinglistsync/ADGroupMailingList.php
Normal file
237
Civi/Mailinglistsync/ADGroupMailingList.php
Normal file
|
@ -0,0 +1,237 @@
|
|||
<?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;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue