diff --git a/appinfo/info.xml b/appinfo/info.xml index 35a9b216ad75861c84ebdedff327b494c024ec54..7ccd4f7b0005365cd49b2d73fba06eb75194edaa 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -28,5 +28,7 @@ OCA\EcloudAccounts\Command\Migrate2FASecrets OCA\EcloudAccounts\Command\MigrateWebmailAddressbooks OCA\EcloudAccounts\Command\MapActiveAttributetoLDAP + OCA\EcloudAccounts\Command\DeleteSendgridContact + OCA\EcloudAccounts\Command\RefreshSendGridSegment diff --git a/lib/Command/DeleteSendgridContact.php b/lib/Command/DeleteSendgridContact.php new file mode 100644 index 0000000000000000000000000000000000000000..58da34d764d9902d3137701d8c14a40f91524dc3 --- /dev/null +++ b/lib/Command/DeleteSendgridContact.php @@ -0,0 +1,74 @@ +sendGridService = $sendGridService; + parent::__construct(); + } + + protected function configure(): void { + $this + ->setName('ecloud-accounts:delete-sendgrid-contact') + ->setDescription('Delete SendGrid contacts within a segment and date range') + ->addOption( + 'segment-id', + null, + InputOption::VALUE_REQUIRED, + 'The ID of the SendGrid segment' + ) + ->addOption( + 'start-date', + null, + InputOption::VALUE_REQUIRED, + 'Start date in YYYY-MM-DD format' + ) + ->addOption( + 'end-date', + null, + InputOption::VALUE_REQUIRED, + 'End date in YYYY-MM-DD format' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output): int { + $segmentId = $input->getOption('segment-id'); + $startDate = $input->getOption('start-date'); + $endDate = $input->getOption('end-date'); + + if (!$segmentId || !$startDate || !$endDate) { + $output->writeln('All options --segment-id, --start-date, and --end-date are required.'); + return Command::FAILURE; + } + + try { + $contacts = $this->sendGridService->fetchContactsFromSegment($segmentId); + $filteredContacts = $this->sendGridService->filterContactsByDateRange($contacts, $startDate, $endDate); + $contactIds = array_column($filteredContacts, 'id'); + + if (empty($contactIds)) { + $output->writeln('No contacts found within the specified date range.'); + return Command::SUCCESS; + } + + $this->sendGridService->deleteContacts($contactIds); + $output->writeln('Successfully deleted ' . count($contactIds) . ' contacts.'); + return Command::SUCCESS; + } catch (Exception $e) { + $output->writeln('Error: ' . $e->getMessage() . ''); + return Command::FAILURE; + } + } +} diff --git a/lib/Command/RefreshSendGridSegment.php b/lib/Command/RefreshSendGridSegment.php new file mode 100644 index 0000000000000000000000000000000000000000..2b8b7e9e6917fee028b40e4882752c297354e101 --- /dev/null +++ b/lib/Command/RefreshSendGridSegment.php @@ -0,0 +1,65 @@ +sendGridService = $sendGridService; + parent::__construct(); + } + + protected function configure(): void { + $this + ->setName('ecloud-accounts:refresh-sendgrid-segment') + ->setDescription('Refreshes the SendGrid segment') + ->addOption( + 'segment-id', + null, + InputOption::VALUE_REQUIRED, + 'The ID of the SendGrid segment' + ) + ->addOption( + 'refresh', + null, + InputOption::VALUE_NONE, + 'Trigger the refresh of the SendGrid segment' + ); + } + + protected function execute(InputInterface $input, OutputInterface $output): int { + + if ($input->getOption('refresh')) { + $segmentId = $input->getOption('segment-id'); + + if (!$segmentId) { + $output->writeln('option --segment-id is required.'); + return Command::FAILURE; + } + try { + $success = $this->sendGridService->refreshSendGridSegment($segmentId); + if ($success) { + $output->writeln('Segment refreshed successfully.'); + return Command::SUCCESS; + } + } catch (Exception $e) { + $output->writeln('Error: ' . $e->getMessage() . ''); + return Command::FAILURE; + } + return 0; + } + + $output->writeln('No action taken.'); + return 0; + } + +} diff --git a/lib/Service/SendGridService.php b/lib/Service/SendGridService.php new file mode 100644 index 0000000000000000000000000000000000000000..1e835d2ee431ef35b968b0ab13d8b67357f06029 --- /dev/null +++ b/lib/Service/SendGridService.php @@ -0,0 +1,131 @@ +config = $config; + $apiKey = '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'; + $this->apiKey = $apiKey; + $this->sendGridClient = new \SendGrid($apiKey); + } + + /** + * Fetch contacts from a specific segment. + * + * @param string $segmentId + * @return array + * @throws Exception + */ + public function fetchContactsFromSegment(string $segmentId): array { + $contacts = []; + $page = 1; + $pageSize = 100; + + do { + $response = $this->sendGridClient->client->contactdb()->segments()->_($segmentId)->recipients()->get(null, [ + 'page' => $page, + 'page_size' => $pageSize, + ]); + + if ($response->statusCode() !== 200) { + throw new Exception("Failed to fetch contacts: " . $response->body()); + } + + $data = json_decode($response->body(), true); + $contacts = array_merge($contacts, $data['recipients'] ?? []); + + if (count($data['recipients'] ?? []) < $pageSize) { + break; + } + + $page++; + } while (true); + + return $contacts; + } + + /** + * Filter contacts by creation date range. + * + * @param array $contacts + * @param string $startDate + * @param string $endDate + * @return array + */ + public function filterContactsByDateRange($contacts, $startDate, $endDate) { + $startTimestamp = is_int($startDate) ? $startDate : strtotime($startDate); + $endTimestamp = is_int($endDate) ? $endDate : strtotime($endDate); + + return array_filter($contacts, function ($contact) use ($startTimestamp, $endTimestamp) { + // Check if `created_at` exists and is numeric + if (!isset($contact['created_at']) || !is_numeric($contact['created_at'])) { + echo "Skipping: Missing or non-numeric created_at.\n"; + return false; + } + + $createdTimestamp = (int) $contact['created_at']; + // Check if the timestamp falls within the range + if ($createdTimestamp >= $startTimestamp && $createdTimestamp <= $endTimestamp) { + return true; + } else { + return false; + } + }); + } + + + /** + * Delete contacts by IDs. + * + * @param array $contactIds + * @throws Exception + */ + public function deleteContacts(array $contactIds): void { + if (empty($contactIds)) { + throw new Exception("No contacts provided for deletion."); + } + + $response = $this->sendGridClient->client->marketing()->contacts()->delete(null, [ + 'ids' => implode(',', $contactIds), + ]); + + if ($response->statusCode() !== 202) { + throw new Exception("Failed to delete contacts: " . $response->body()); + } + } + + public function refreshSendGridSegment($segmentId) { + $data = [ + 'user_time_zone' => 'America/Chicago' + ]; + + try { + $response = $this->sendGridClient->client + ->marketing() + ->segments() + ->_($segmentId) + ->refresh() + ->post($data); + + if ($response->statusCode() === 202) { + return true; + } else { + throw new Exception("Failed to refresh contacts: " . $response->body()); + } + } catch (Exception $e) { + throw new Exception('Caught exception: ' . $e->getMessage()); + } + } +}