Skip to content

Commit c6a6862

Browse files
Merge pull request #248 from JLG-WOCFR-DEV/codex/implement-notification-settings-enhancements
Add notification channel toggles and test email flow
2 parents 91e4c33 + 016118c commit c6a6862

File tree

4 files changed

+457
-26
lines changed

4 files changed

+457
-26
lines changed

liens-morts-detector-jlg/assets/js/blc-admin-scripts.js

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,169 @@ jQuery(document).ready(function($) {
9494
window.blcAdmin = window.blcAdmin || {};
9595
window.blcAdmin.accessibility = accessibility;
9696

97+
function createNoticeElement(type, message) {
98+
var classes = 'notice';
99+
switch (type) {
100+
case 'success':
101+
classes += ' notice-success';
102+
break;
103+
case 'error':
104+
classes += ' notice-error';
105+
break;
106+
case 'warning':
107+
classes += ' notice-warning';
108+
break;
109+
default:
110+
classes += ' notice-info';
111+
break;
112+
}
113+
114+
var $notice = $('<div>', { class: classes });
115+
if (message) {
116+
$('<p>').text(message).appendTo($notice);
117+
}
118+
119+
return $notice;
120+
}
121+
122+
(function setupTestEmailButton() {
123+
var config = window.blcAdminNotifications || null;
124+
if (!config || !config.nonce) {
125+
return;
126+
}
127+
128+
var $button = $('#blc-send-test-email');
129+
if (!$button.length) {
130+
return;
131+
}
132+
133+
var $spinner = $('#blc-test-email-spinner');
134+
var $feedback = $('#blc-test-email-feedback');
135+
var $recipients = $('#blc_notification_recipients');
136+
var $linkToggle = $('#blc_notification_links_enabled');
137+
var $imageToggle = $('#blc_notification_images_enabled');
138+
var isSending = false;
139+
140+
function ensureFeedbackContainer() {
141+
if ($feedback && $feedback.length) {
142+
return $feedback;
143+
}
144+
145+
var $container = $('<div>', {
146+
id: 'blc-test-email-feedback',
147+
class: 'blc-test-email-feedback',
148+
'aria-live': 'polite'
149+
});
150+
151+
var $targetCell = $button.closest('td');
152+
if ($targetCell.length) {
153+
$targetCell.append($container);
154+
} else {
155+
$button.after($container);
156+
}
157+
158+
$feedback = $container;
159+
return $feedback;
160+
}
161+
162+
function showFeedback(type, message) {
163+
var $container = ensureFeedbackContainer();
164+
$container.empty();
165+
166+
if (!message) {
167+
return;
168+
}
169+
170+
var $notice = createNoticeElement(type, message);
171+
$container.append($notice);
172+
173+
var politeness = type === 'error' ? 'assertive' : 'polite';
174+
accessibility.speak(message, politeness);
175+
}
176+
177+
function setSending(state) {
178+
isSending = state;
179+
$button.prop('disabled', state);
180+
181+
if ($spinner.length) {
182+
$spinner.toggleClass('is-active', state);
183+
}
184+
185+
if (state) {
186+
$button.attr('aria-busy', 'true');
187+
} else {
188+
$button.removeAttr('aria-busy');
189+
}
190+
}
191+
192+
$button.on('click', function(event) {
193+
event.preventDefault();
194+
195+
if (isSending) {
196+
return;
197+
}
198+
199+
var recipientsValue = '';
200+
if ($recipients.length) {
201+
recipientsValue = $recipients.val();
202+
}
203+
204+
if (!recipientsValue || $.trim(String(recipientsValue)) === '') {
205+
showFeedback('warning', config.missingRecipientsText || '');
206+
return;
207+
}
208+
209+
var datasetTypes = [];
210+
if ($linkToggle.length && $linkToggle.is(':checked')) {
211+
datasetTypes.push('link');
212+
}
213+
if ($imageToggle.length && $imageToggle.is(':checked')) {
214+
datasetTypes.push('image');
215+
}
216+
217+
if (!datasetTypes.length) {
218+
showFeedback('warning', config.missingChannelText || '');
219+
return;
220+
}
221+
222+
var ajaxEndpoint = config.ajaxUrl || (typeof window.ajaxurl !== 'undefined' ? window.ajaxurl : '');
223+
if (!ajaxEndpoint) {
224+
showFeedback('error', config.errorText || '');
225+
return;
226+
}
227+
228+
setSending(true);
229+
if (config.sendingText) {
230+
showFeedback('info', config.sendingText);
231+
}
232+
233+
$.post(ajaxEndpoint, {
234+
action: config.action,
235+
_ajax_nonce: config.nonce,
236+
recipients: recipientsValue,
237+
dataset_types: datasetTypes
238+
}).done(function(response) {
239+
if (response && response.success) {
240+
var message = (response.data && response.data.message) ? response.data.message : (config.successText || '');
241+
var type = (response.data && response.data.partial) ? 'warning' : 'success';
242+
if (response.data && response.data.partial && !response.data.message && config.partialSuccessText) {
243+
message = config.partialSuccessText;
244+
}
245+
showFeedback(type, message);
246+
} else {
247+
var errorMessage = (response && response.data && response.data.message)
248+
? response.data.message
249+
: (config.errorText || '');
250+
showFeedback('error', errorMessage);
251+
}
252+
}).fail(function() {
253+
showFeedback('error', config.errorText || '');
254+
}).always(function() {
255+
setSending(false);
256+
});
257+
});
258+
})();
259+
97260
(function announceBulkNotice() {
98261
var $notice = $('.blc-bulk-notice');
99262

liens-morts-detector-jlg/includes/blc-scanner.php

Lines changed: 84 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -586,29 +586,9 @@ function blc_make_image_scan_controller(ImageScanQueue $queue) {
586586
* @return string[]
587587
*/
588588
function blc_get_notification_recipients_list() {
589-
$raw_recipients = (string) get_option('blc_notification_recipients', '');
590-
if ($raw_recipients === '') {
591-
return [];
592-
}
593-
594-
$candidates = preg_split('/[\r\n,]+/', $raw_recipients);
595-
if (!is_array($candidates)) {
596-
return [];
597-
}
589+
$stored = get_option('blc_notification_recipients', '');
598590

599-
$recipients = [];
600-
foreach ($candidates as $candidate) {
601-
$email = sanitize_email(trim((string) $candidate));
602-
if ($email === '') {
603-
continue;
604-
}
605-
606-
if (is_email($email)) {
607-
$recipients[$email] = $email;
608-
}
609-
}
610-
611-
return array_values($recipients);
591+
return blc_parse_notification_recipients($stored);
612592
}
613593

614594
/**
@@ -619,26 +599,67 @@ function blc_get_notification_recipients_list() {
619599
* @return void
620600
*/
621601
function blc_maybe_send_scan_summary($dataset_type) {
602+
if (!blc_is_notification_channel_enabled($dataset_type)) {
603+
return;
604+
}
605+
622606
$recipients = blc_get_notification_recipients_list();
623607
if ($recipients === []) {
624608
return;
625609
}
626610

611+
$email = blc_generate_scan_summary_email($dataset_type);
612+
if ($email === null) {
613+
return;
614+
}
615+
616+
wp_mail($recipients, $email['subject'], $email['message']);
617+
}
618+
619+
/**
620+
* Check if a notification channel is enabled.
621+
*
622+
* @param string $dataset_type Dataset type ('link' or 'image').
623+
*
624+
* @return bool
625+
*/
626+
function blc_is_notification_channel_enabled($dataset_type) {
627+
$dataset_type = (string) $dataset_type;
628+
629+
if ($dataset_type === 'link') {
630+
return (bool) get_option('blc_notification_links_enabled', true);
631+
}
632+
633+
if ($dataset_type === 'image') {
634+
return (bool) get_option('blc_notification_images_enabled', true);
635+
}
636+
637+
return false;
638+
}
639+
640+
/**
641+
* Build the scan summary email payload for a dataset type.
642+
*
643+
* @param string $dataset_type Dataset type ('link' or 'image').
644+
*
645+
* @return array<string, mixed>|null
646+
*/
647+
function blc_generate_scan_summary_email($dataset_type) {
627648
global $wpdb;
628649
if (!isset($wpdb) || !is_object($wpdb) || !isset($wpdb->prefix)) {
629-
return;
650+
return null;
630651
}
631652

632653
$dataset_type = (string) $dataset_type;
633654
if ($dataset_type !== 'link' && $dataset_type !== 'image') {
634-
return;
655+
return null;
635656
}
636657

637658
$table_name = $wpdb->prefix . 'blc_broken_links';
638659
$broken_count = 0;
639660
$row_types = blc_get_dataset_row_types($dataset_type);
640661
if ($row_types === []) {
641-
return;
662+
return null;
642663
}
643664

644665
if (method_exists($wpdb, 'prepare') && method_exists($wpdb, 'get_var')) {
@@ -726,7 +747,44 @@ function blc_maybe_send_scan_summary($dataset_type) {
726747

727748
$message = implode(PHP_EOL, $message_lines);
728749

729-
wp_mail($recipients, $subject, $message);
750+
return [
751+
'subject' => $subject,
752+
'message' => $message,
753+
'dataset_type' => $dataset_type,
754+
'broken_count' => $broken_count,
755+
];
756+
}
757+
758+
/**
759+
* Parse a raw recipient string into a list of valid email addresses.
760+
*
761+
* @param mixed $raw_recipients Raw input value.
762+
*
763+
* @return string[]
764+
*/
765+
function blc_parse_notification_recipients($raw_recipients) {
766+
if (!is_scalar($raw_recipients)) {
767+
return [];
768+
}
769+
770+
$candidates = preg_split('/[\r\n,;]+/', (string) $raw_recipients);
771+
if (!is_array($candidates)) {
772+
return [];
773+
}
774+
775+
$recipients = [];
776+
foreach ($candidates as $candidate) {
777+
$email = sanitize_email(trim((string) $candidate));
778+
if ($email === '') {
779+
continue;
780+
}
781+
782+
if (is_email($email)) {
783+
$recipients[$email] = $email;
784+
}
785+
}
786+
787+
return array_values($recipients);
730788
}
731789

732790
/**

0 commit comments

Comments
 (0)