PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / 6.2.1
MainWP Dashboard: Self-hosted WordPress Management for Agencies v6.2.1
6.2.2 6.2.1 6.2 6.1.8 6.1.7 6.1.6 6.1.5 6.1.4 6.1.3 6.1.2 6.1.1 6.1 6.0.12 6.0.11 4.6.0.1 5.0 5.0.1 5.0.2 5.0.3 5.0.3.1 5.0.3.2 5.1 5.1.1 5.2 5.2.1 All 155 releases
mainwp / assets / js / mainwp-password-policy.js

mainwp-password-policy.js in MainWP Dashboard: Self-hosted WordPress Management for Agencies 6.2.1, at assets/js/mainwp-password-policy.js

344 lines 10.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * MainWP Password Policy Settings - AJAX Update Handler
3 *
4 * Handles progressive AJAX updates of password policy settings across sites.
5 * Matches the sync sites functionality pattern.
6 */
7
8 jQuery(document).ready(function($) {
9 $('#mainwp_password_policy_window').on('change', function() {
10 if ($(this).val() === '0') {
11 $('#mainwp-password-policy-additional-settings').slideUp();
12 } else {
13 $('#mainwp-password-policy-additional-settings').slideDown();
14 }
15 });
16
17 setTimeout(function() {
18 if ($('#overwrite-enabled-checkbox').length) {
19 $('#overwrite-enabled-checkbox').checkbox({
20 onChecked: function() {
21 $('#individual-settings-fields').slideDown(300);
22 $('#save-individual-password-policy').slideDown(300);
23 },
24 onUnchecked: function() {
25 $('#individual-settings-fields').slideUp(300);
26 $('#save-individual-password-policy').slideUp(300);
27 }
28 });
29 }
30
31 if ($('#individual_max_age_days').length) {
32 let initialValue = $('#individual_max_age_days').val();
33
34 if (initialValue === '0') {
35 $('#individual-additional-settings').hide();
36 }
37
38 $('#individual_max_age_days').dropdown({
39 onChange: function(value) {
40 if (value === '0') {
41 $('#individual-additional-settings').slideUp(300);
42 } else {
43 $('#individual-additional-settings').slideDown(300);
44 }
45 }
46 });
47 }
48
49 if ($('#individual_show_notices_to').length) {
50 $('#individual_show_notices_to').dropdown();
51 }
52 }, 300);
53
54 $(document).on('click', '#save-individual-password-policy', function(e) {
55 e.preventDefault();
56
57 let button = $(this);
58 let form = $('#mainwp-individual-password-policy-form');
59 let statusDiv = $('#individual-password-policy-status');
60
61 if (!form.length) {
62 return;
63 }
64
65 button.addClass('loading disabled');
66 statusDiv.hide();
67
68 let formData = {
69 action: 'mainwp_password_policy_save_individual',
70 site_id: form.find('input[name="site_id"]').val(),
71 overwrite_enabled: $('#overwrite_enabled').is(':checked') ? '1' : '0',
72 max_age_days: form.find('select[name="max_age_days"]').val(),
73 due_soon_message: form.find('input[name="due_soon_message"]').val(),
74 overdue_message: form.find('input[name="overdue_message"]').val(),
75 show_notices_to: form.find('select[name="show_notices_to"]').val()
76 };
77
78 let data = mainwp_secure_data(formData);
79
80 $.ajax({
81 type: 'POST',
82 url: ajaxurl,
83 data: data,
84 success: function(response) {
85 button.removeClass('loading disabled');
86
87 if (response.success) {
88 statusDiv
89 .removeClass('red')
90 .addClass('green icon')
91 .html(response.data.message)
92 .show();
93
94 setTimeout(function() {
95 location.reload();
96 }, 1500);
97 } else {
98 statusDiv
99 .removeClass('green icon')
100 .addClass('red icon')
101 .html(response?.data?.message ?? MainWP.I18n.t('An error occurred', 'mainwp'))
102 .show();
103
104 $('html, body').animate({
105 scrollTop: statusDiv.offset().top - 100
106 }, 500);
107 }
108 },
109 error: function(xhr, status, error) {
110 button.removeClass('loading disabled');
111 statusDiv
112 .removeClass('green icon')
113 .addClass('red icon')
114 .html(MainWP.I18n.t('AJAX request failed', 'mainwp'))
115 .show();
116
117 $('html, body').animate({
118 scrollTop: statusDiv.offset().top - 100
119 }, 500);
120 },
121 dataType: 'json'
122 });
123 });
124 });
125
126 globalThis.mainwp_password_policy_vars = {
127 sitesToUpdate: [],
128 sitesTotal: 0,
129 sitesLeft: 0,
130 sitesDone: 0,
131 currentSite: 0,
132 updateRunning: false,
133 currentThreads: 0,
134 maxThreads: 3,
135 settings: {},
136 sitesData: {}
137 };
138
139 /**
140 * Start the password policy update process
141 *
142 * @param {array} siteIds Array of site IDs to update
143 * @param {object} sitesData Object containing site data keyed by site ID
144 * @param {object} settings Password policy settings to apply
145 */
146 globalThis.mainwp_password_policy_start_update = function(siteIds, sitesData, settings) {
147 mainwp_password_policy_vars.sitesToUpdate = siteIds;
148 mainwp_password_policy_vars.sitesData = sitesData;
149 mainwp_password_policy_vars.settings = settings;
150 mainwp_password_policy_vars.currentSite = 0;
151 mainwp_password_policy_vars.sitesDone = 0;
152 mainwp_password_policy_vars.sitesTotal = siteIds.length;
153 mainwp_password_policy_vars.sitesLeft = siteIds.length;
154 mainwp_password_policy_vars.updateRunning = true;
155
156 jQuery('#mainwp-password-policy-sites-list').html('');
157
158 for (const siteId of siteIds) {
159 let siteName = sitesData[siteId].name;
160 jQuery('#mainwp-password-policy-sites-list').append(
161 '<div class="item">' +
162 '<div class="right floated content">' +
163 '<div class="password-policy-site-status" siteid="' + siteId + '">' +
164 '<span data-position="left center" data-inverted="" data-tooltip="' + MainWP.I18n.t('Pending', 'mainwp') + '">' +
165 '<i class="clock outline icon"></i>' +
166 '</span>' +
167 '</div>' +
168 '</div>' +
169 '<div class="content">' +
170 jQuery('<div>').text(siteName).html() +
171 '</div>' +
172 '</div>'
173 );
174 }
175
176 jQuery('#mainwp-password-policy-progress-modal .mainwp-modal-progress').progress({
177 value: 0,
178 total: siteIds.length
179 });
180
181 mainwp_password_policy_update_progress_status();
182
183 jQuery('#mainwp-password-policy-progress-modal').modal({
184 closable: false
185 }).modal('show');
186
187 mainwp_password_policy_loop_next();
188 };
189
190 /**
191 * Process next batch of sites
192 */
193 let mainwp_password_policy_loop_next = function() {
194 while (mainwp_password_policy_vars.updateRunning &&
195 (mainwp_password_policy_vars.currentThreads < mainwp_password_policy_vars.maxThreads) &&
196 (mainwp_password_policy_vars.sitesLeft > 0)) {
197 mainwp_password_policy_update_next();
198 }
199 };
200
201 /**
202 * Update next site in queue
203 */
204 let mainwp_password_policy_update_next = function() {
205 mainwp_password_policy_vars.currentThreads++;
206 mainwp_password_policy_vars.sitesLeft--;
207
208 let siteId = mainwp_password_policy_vars.sitesToUpdate[mainwp_password_policy_vars.currentSite++];
209
210 mainwp_password_policy_update_site_status(
211 siteId,
212 '<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Updating...', 'mainwp') + '">' +
213 '<i class="sync alternate loading icon"></i>' +
214 '</span>'
215 );
216
217 let data = mainwp_secure_data({
218 action: 'mainwp_password_policy_update_site',
219 site_id: siteId,
220 max_age_days: mainwp_password_policy_vars.settings.max_age_days,
221 due_soon_days: 7,
222 due_soon_message: mainwp_password_policy_vars.settings.due_soon_message,
223 overdue_message: mainwp_password_policy_vars.settings.overdue_message,
224 show_notices_to: mainwp_password_policy_vars.settings.show_notices_to
225 });
226
227 mainwp_password_policy_update_next_int(siteId, data, 0);
228 };
229
230 /**
231 * Execute AJAX request with retry logic
232 */
233 let mainwp_password_policy_update_next_int = function(siteId, data, errors) {
234 jQuery.ajax({
235 type: 'POST',
236 url: ajaxurl,
237 data: data,
238 success: function(pSiteId) {
239 return function(response) {
240 mainwp_password_policy_vars.currentThreads--;
241
242 if (response?.success) {
243 mainwp_password_policy_update_site_status(
244 pSiteId,
245 '<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Updated successfully', 'mainwp') + '">' +
246 '<i class="check green icon"></i>' +
247 '</span>',
248 true
249 );
250 } else {
251 let errorMsg = response?.error ? response.error : MainWP.I18n.t('Unknown error', 'mainwp');
252 if ( response?.debug) {
253 console.log('Password policy update debug (Site ' + pSiteId + '):', response.debug);
254 errorMsg += ' (See console for details)';
255 }
256 mainwp_password_policy_update_site_status(
257 pSiteId,
258 '<span data-inverted="" data-position="left center" data-tooltip="' + errorMsg + '">' +
259 '<i class="exclamation red icon"></i>' +
260 '</span>'
261 );
262 }
263
264 mainwp_password_policy_update_done();
265 }
266 }(siteId),
267 error: function(pSiteId, pData, pErrors) {
268 return function() {
269 if (pErrors > 5) {
270 mainwp_password_policy_vars.currentThreads--;
271 mainwp_password_policy_update_site_status(
272 pSiteId,
273 '<span data-inverted="" data-position="left center" data-tooltip="' + MainWP.I18n.t('Process timed out. Please try again.', 'mainwp') + '">' +
274 '<i class="exclamation yellow icon"></i>' +
275 '</span>'
276 );
277 mainwp_password_policy_update_done();
278 } else {
279 pErrors++;
280 mainwp_password_policy_update_next_int(pSiteId, pData, pErrors);
281 }
282 }
283 }(siteId, data, errors),
284 dataType: 'json'
285 });
286 };
287
288 /**
289 * Update visual status for a site
290 *
291 * @param {int} siteId Site ID
292 * @param {string} statusHtml HTML content for status
293 * @param {bool} isSuccess Whether update was successful
294 */
295 let mainwp_password_policy_update_site_status = function(siteId, statusHtml, isSuccess) {
296 jQuery('.password-policy-site-status[siteid="' + siteId + '"]').html(statusHtml);
297 if ( isSuccess !== undefined && isSuccess) {
298 let row = jQuery('.password-policy-site-status[siteid="' + siteId + '"]').closest('.item');
299 jQuery(row).insertAfter(jQuery('#mainwp-password-policy-sites-list .item').last());
300 }
301 };
302
303 /**
304 * Update overall progress status
305 */
306 let mainwp_password_policy_update_progress_status = function() {
307 let statusText = mainwp_password_policy_vars.sitesDone + ' / ' + mainwp_password_policy_vars.sitesTotal + ' ' + MainWP.I18n.t('updated', 'mainwp');
308 jQuery('#mainwp-password-policy-progress-modal .mainwp-modal-progress').find('.label').html(statusText);
309 jQuery('#mainwp-password-policy-progress-modal .mainwp-modal-progress').progress('set progress', mainwp_password_policy_vars.sitesDone);
310 };
311
312 /**
313 * Handle completion of a site update
314 */
315 let mainwp_password_policy_update_done = function() {
316 if (!mainwp_password_policy_vars.updateRunning) {
317 return;
318 }
319
320 mainwp_password_policy_vars.sitesDone++;
321
322 if (mainwp_password_policy_vars.sitesDone > mainwp_password_policy_vars.sitesTotal) {
323 mainwp_password_policy_vars.sitesDone = mainwp_password_policy_vars.sitesTotal;
324 }
325
326 mainwp_password_policy_update_progress_status();
327
328 if (mainwp_password_policy_vars.sitesDone === mainwp_password_policy_vars.sitesTotal) {
329 let successSites = jQuery('#mainwp-password-policy-progress-modal .check.green.icon').length;
330 if (mainwp_password_policy_vars.sitesDone === successSites) {
331 mainwp_password_policy_vars.updateRunning = false;
332 setTimeout(function() {
333 jQuery('#mainwp-password-policy-progress-modal').modal('hide');
334 location.reload();
335 }, 3000);
336 } else {
337 mainwp_password_policy_vars.updateRunning = false;
338 }
339 return;
340 }
341
342 mainwp_password_policy_loop_next();
343 };
344