at path:ROOT / clients / templates / six / store / ox / manage.tpl
run:R W Run
49 By
2026-04-08 19:33:21
R W Run
8.91 KB
2026-04-08 19:33:21
R W Run
47.33 KB
2026-04-08 19:33:21
R W Run
error_log
📄manage.tpl
1<div id="oxSuccess" class="alert alert-success hidden">
2 <i class="fas fa-check fa-fw"></i>
3 <span></span>
4</div>
5<div id="oxLoadError" class="alert alert-danger hidden">
6 <i class="fas fa-times fa-fw"></i>
7 <span></span>
8</div>
9
10<p>{lang key='ox.intro'}</p>
11<p>{lang key='ox.alias.intro'}</p>
12
13<p>
14 <form action="{$upgradeUrl}" method="post">
15 <span id="accountCount">
16 <span id="accountCount">
17 {lang key='ox.accountCount' number='-' limit=$model->qty}
18 </span>
19 </span>
20 <input type="hidden" name="isproduct" value="{$isService}">
21 <input type="hidden" name="serviceid" value="{$model->id}">
22 <button type="submit" class="btn-link no-padding">{lang key='upgrade'}</button>
23 </form>
24</p>
25
26<div class="compact-control-bar">
27 <button id="btnRefresh" type="button" class="btn btn-sm btn-default disabled pull-right" disabled="disabled">
28 <i class="fas fa-sync-alt fa-spin" aria-hidden="true"></i>
29 {lang key='ox.refresh'}
30 </button>
31 <button id="btnAddAccount" type="button" class="btn btn-default btn-sm">
32 <i class="fal fa-plus"></i>
33 {lang key='ox.createUser'}
34 </button>
35</div>
36
37<table class="ox-table-accounts table">
38 <thead>
39 <tr>
40 <th>{lang key='ox.emailAddress'}</th>
41 <th width="25%">{lang key='ox.mailboxSize'}</th>
42 <th width="50%" class="invisible"></th>
43 </tr>
44 </thead>
45 <tbody>
46 <tr class="loading">
47 <td colspan="3">
48 <i class="fas fa-sync-alt fa-spin" aria-hidden="true"></i>
49 {lang key='loading'}
50 </td>
51 </tr>
52 <tr class="no-accounts hidden">
53 <td colspan="3">{lang key='ox.noAccounts'}</td>
54 </tr>
55 </tbody>
56 <tbody class="cloneAccountsBody hidden"
57 data-account-id=""
58 data-account=""
59 data-first-name=""
60 data-last-name=""
61 data-display-name=""
62 >
63 <tr>
64 <td>
65 <span class="account"></span>@{$domain}<br/>
66 <i class="fas fa-chevron-right fa-xs fa-fw"></i>
67 <span class="email-aliases">
68 {lang key='ox.alias.emailAliases'}: <span class="alias-count"></span>
69 </span>
70 </td>
71 <td><span class="limit"></span>GB</td>
72 <td class="text-right">
73 <div class="menu-sm">
74 <div class="btn-group" role="group">
75 <button type="button" class="btn btn-default btn-sm dropdown-toggle dropdown-hamburger" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
76 <i class="fas fa-bars"></i>
77 </button>
78 <ul class="dropdown-menu dropdown-menu-right">
79 <li><a href="#" class="manage-account">{lang key='ox.manageAccount'}</a></li>
80 <li><a href="#" class="set-ox-password">{lang key='ox.setPassword'}</a></li>
81 <li><a href="#" class="list-group-item-danger ox-delete">{lang key='ox.delete'}</a></li>
82 </ul>
83 </div>
84 </div>
85 <div class="menu-md">
86 <div class="btn-group" role="group">
87 <button class="btn btn-default btn-sm manage-account">{lang key='ox.manageAccount'}</button>
88 <button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
89 <span class="caret"></span>
90 </button>
91 <ul class="dropdown-menu dropdown-menu-right">
92 <li><a href="#" class="set-ox-password">{lang key='ox.setPassword'}</a></li>
93 <li><a href="#" class="list-group-item-danger ox-delete">{lang key='ox.delete'}</a></li>
94 </ul>
95 </div>
96 </div>
97 <div class="menu-lg">
98 <div class="btn-group" role="group">
99 <button class="btn btn-default btn-sm manage-account">{lang key='ox.manageAccount'}</button>
100 <button class="btn btn-default btn-sm set-ox-password">{lang key='ox.setPassword'}</button>
101 <button class="btn btn-danger btn-sm ox-delete">{lang key='ox.delete'}</button>
102 </div>
103 </div>
104 </td>
105 </tr>
106 </tbody>
107 <tbody class="cloneAliasesBody hidden" data-account-id="">
108 <tr>
109 <td colspan="3">
110 <table class="table">
111 <tr class="create-alias" data-alias="">
112 <td align="right">
113 <div class="input-group input-group-xs">
114 <input type="text" name="alias" class="form-control">
115 <span class="input-group-addon">
116 @{$domain}
117 </span>
118 </div>
119 </td>
120 <td>
121 <button class="btn btn-primary btn-xs ox-create-alias">
122 <span class="loader hidden">
123 <i class="far fa-sync-alt fa-spin" aria-hidden="true"></i>
124 </span>
125 <span class="create-string">
126 {lang key='ox.alias.createButton'}
127 </span>
128 </button>
129 </td>
130 <td>&nbsp;</td>
131 </tr>
132 </table>
133 </td>
134 </tr>
135 </tbody>
136 <tr class="cloneAliasRow hidden"
137 data-alias=""
138 >
139 <td colspan="2"><span class="alias"></span>@{$domain}</td>
140 <td class="text-right">
141 <div class="btn-group" role="group">
142 <button class="btn btn-default btn-xs ox-delete-alias">{lang key='ox.delete'}</button>
143 </div>
144 </td>
145 </tr>
146</table>
147
148<ul class="nav nav-tabs nav-tabs-overflow">
149 <li class="active">
150 <a href="#retrievalsettings" data-toggle="tab">
151 <i class="far fa-envelope fa-fw"></i>
152 {lang key='ox.settings.retrieval'}
153 </a>
154 </li>
155 <li>
156 <a href="#davsettings" data-toggle="tab">
157 <i class="far fa-calendar-alt fa-fw"></i>
158 {lang key='ox.settings.davSettings'}
159 </a>
160 </li>
161 <li>
162 <a href="#usage" data-toggle="tab">
163 <i class="far fa-file-alt fa-fw"></i>
164 {lang key='ox.settings.usageInstructions'}
165 </a>
166 </li>
167 <li class="hidden" id="migrationNav">
168 <a href="#migration" data-toggle="tab">
169 <i class="far fa-file-alt fa-fw"></i>
170 {lang key='ox.settings.migrationTitle'}
171 </a>
172 </li>
173</ul>
174<div class="tab-content product-details-tab-container" style="font-size:0.9em;">
175 <div class="tab-pane fade in active" id="retrievalsettings">
176 <p>{lang key='ox.settings.retrievalIntro'}</p>
177 <table class="table">
178 <tbody>
179 <tr>
180 <td>{lang key='ox.settings.username'}</td>
181 <td>{lang key='ox.settings.email' domain=$domain}</td>
182 </tr>
183 <tr>
184 <td>{lang key='clientareapassword'}</td>
185 <td>{lang key='ox.settings.password'}</td>
186 </tr>
187 <tr>
188 <td>{lang key='ox.settings.pop'}</td>
189 <td>
190 <span class="pop-hostname">
191 <i class="fas fa-sync-alt fa-spin" aria-hidden="true"></i>
192 {lang key='loading'}
193 </span><br>
194 <span class="pop-port"></span>
195 </td>
196 </tr>
197 <tr>
198 <td>{lang key='ox.settings.incoming'}</td>
199 <td>
200 <span class="incoming-hostname">
201 <i class="fas fa-sync-alt fa-spin" aria-hidden="true"></i>
202 {lang key='loading'}
203 </span><br>
204 <span class="incoming-port"></span>
205 </td>
206 </tr>
207 <tr>
208 <td>{lang key='ox.settings.outgoing'}</td>
209 <td>
210 <span class="outgoing-hostname">
211 <i class="fas fa-sync-alt fa-spin" aria-hidden="true"></i>
212 {lang key='loading'}
213 </span><br>
214 <span class="outgoing-port"></span>
215 </td>
216 </tr>
217 </tbody>
218 </table>
219 </div>
220 <div class="tab-pane fade" id="davsettings">
221 <p>{lang key='ox.settings.davSettingsIntro'}</p>
222 <table class="table">
223 <tbody>
224 <tr>
225 <td>{lang key='ox.settings.username'}</td>
226 <td>{lang key='ox.settings.email' domain=$domain}</td>
227 </tr>
228 <tr>
229 <td>{lang key='clientareapassword'}</td>
230 <td>{lang key='ox.settings.caldavPassword'}</td>
231 </tr>
232 <tr>
233 <td>{lang key='ox.settings.serverUrl'}</td>
234 <td>
235 <span class="calendar-server">
236 <i class="fas fa-sync-alt fa-spin" aria-hidden="true"></i>
237 {lang key='loading'}
238 </span>
239 </td>
240 </tr>
241 </tbody>
242 </table>
243 </div>
244 <div class="tab-pane fade" id="usage">
245 <table class="table">
246 <thead id="tablePanelUsageHead">
247 <tr class="loading">
248 <td>
249 <i class="fas fa-sync-alt fa-spin" aria-hidden="true"></i>
250 {lang key='loading'}
251 </td>
252 </tr>
253 </thead>
254 <tbody id="tablePanelUsage">
255 </tbody>
256 </table>
257 </div>
258 <div class="tab-pane fade hidden" id="migration">
259 <p>{lang key="ox.settings.migrationIntro"}</p>
260 <div>
261 <a class="migration-url btn btn-info btn-block btn-lg" href="#" target="_blank"
262 >{lang key="ox.settings.migrationLaunch"}</a>
263 </div>
264 </div>
265</div>
266
267<br><br>
268
269<form id="frmOxAddAccount" action="{$addAccountUrl}" method="post">
270 <div class="modal fade" id="modalAddAccount">
271 <div class="modal-dialog modal-lg">
272 <div class="modal-content panel-primary">
273 <div class="modal-header panel-heading">
274 <button type="button" class="close" data-dismiss="modal" aria-label="{lang key='close'}"><span aria-hidden="true">&times;</span></button>
275 <h4 class="modal-title" id="modalAddAccountTitle">
276 {lang key='ox.createUser'}
277 </h4>
278 </div>
279 <div class="modal-body panel-body" id="modalSetPasswordBody">
280 <div class="alert alert-danger modal-error hidden">
281 <i class="fas fa-times fa-fw"></i>
282 <span></span>
283 </div>
284 <div class="row">
285 <div class="col-md-6">
286 <div class="form-group">
287 <label for="inputFirstName">{lang key='orderForm.firstName'}</label>
288 <input id="inputFirstName" type="text" autocomplete="off" class="form-control required" name="first">
289 <span class="field-error-msg">{lang key='ox.required.firstName'}</span>
290 </div>
291 </div>
292 <div class="col-md-6">
293 <div class="form-group">
294 <label for="inputLastName">{lang key='orderForm.lastName'}</label>
295 <input id="inputLastName" type="text" autocomplete="off" class="form-control required" name="last">
296 <span class="field-error-msg">{lang key='ox.required.lastName'}</span>
297 </div>
298 </div>
299 </div>
300 <div class="row">
301 <div class="col-md-6">
302 <div class="form-group">
303 <label for="inputDisplayName">{lang key='ox.displayName'}</label>
304 <input id="inputDisplayName" type="text" autocomplete="off" class="form-control required" name="display">
305 <span class="field-error-msg">{lang key='ox.required.displayName'}</span>
306 </div>
307 </div>
308 <div class="col-md-6">
309 <div class="form-group">
310 <label for="inputEmailAddress">{lang key='orderForm.emailAddress'}</label>
311 <div class="input-group">
312 <input id="inputEmailAddress" type="text" autocomplete="off" class="form-control required" name="email">
313 <span class="input-group-addon">@{$domain}</span>
314 </div>
315 <span class="field-error-msg">{lang key='ox.required.email'}</span>
316 </div>
317 </div>
318 </div>
319 <div class="row">
320 <div class="col-md-6">
321 <div class="form-group">
322 <label for="inputPassword">{lang key='clientareapassword'}</label>
323 <div class="input-group">
324 <input type="password" class="form-control required" name="password" id="inputPassword" data-error-threshold="{$pwStrengthErrorThreshold}" data-warning-threshold="{$pwStrengthWarningThreshold}" placeholder="{lang key="loginpassword"}" autocomplete="off" />
325 <span class="input-group-btn">
326 <button type="button" class="btn btn-default generate-password" data-targetfields="inputPassword,inputConfirmPassword">
327 {lang key="generatePassword.btnShort"}
328 </button>
329 </span>
330 </div>
331 <span class="field-error-msg">{lang key='ox.required.password'}</span>
332 <div class="password-strength-meter">
333 <div class="progress" style="height: 10px; margin-top: 10px">
334 <div class="progress-bar progress-bar-success progress-bar-striped" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" id="passwordStrengthMeterBar">
335 </div>
336 </div>
337 <p class="text-center small text-muted" id="passwordStrengthTextLabel">{lang key="pwstrength"}: {lang key="pwstrengthenter"}</p>
338 </div>
339 </div>
340 </div>
341 <div class="col-md-6">
342 <div class="form-group">
343 <label for="inputConfirmPassword">{lang key='clientareaconfirmpassword'}</label>
344 <input id="inputConfirmPassword" type="password" autocomplete="off" class="form-control required match" data-match-field="inputPassword" name="password2">
345 <span class="field-error-msg">{lang key='ox.required.passwordMatch'}</span>
346 </div>
347 </div>
348 </div>
349 </div>
350 <div class="modal-footer panel-footer">
351 <div class="pull-left loader hidden">
352 <i class="fas fa-sync-alt fa-spin"></i>
353 {lang key='loading'}
354 </div>
355 <button type="button" class="btn btn-default" data-dismiss="modal">
356 {lang key='close'}
357 </button>
358 <button type="button" class="btn btn-primary ox-submit-button">
359 {lang key='orderForm.add'}
360 </button>
361 </div>
362 </div>
363 </div>
364 </div>
365</form>
366<form id="frmOxManageAccount" action="{$manageAccountUrl}" method="post">
367 <div class="modal fade" id="modalManageAccount">
368 <input type="hidden" value="" name="account">
369 <div class="modal-dialog">
370 <div class="modal-content panel-primary">
371 <div class="modal-header panel-heading">
372 <button type="button" class="close" data-dismiss="modal" aria-label="{lang key='close'}"><span aria-hidden="true">&times;</span></button>
373 <h4 class="modal-title" id="modalManageAccountTitle">
374 {lang key='ox.manageAccount'}
375 </h4>
376 </div>
377 <div class="modal-body panel-body" id="modalSetPasswordBody">
378 <div class="alert alert-danger modal-error hidden">
379 <i class="fas fa-times fa-fw"></i>
380 <span></span>
381 </div>
382 <div class="form-group">
383 <label for="inputManageDisplayName">{lang key='ox.displayName'}</label>
384 <input id="inputManageDisplayName" type="text" autocomplete="off" class="form-control required" name="display">
385 <span class="field-error-msg">{lang key='ox.required.displayName'}</span>
386 </div>
387 <div class="form-group">
388 <label for="inputManageFirstName">{lang key='orderForm.firstName'}</label>
389 <input id="inputManageFirstName" type="text" autocomplete="off" class="form-control required" name="first">
390 <span class="field-error-msg">{lang key='ox.required.firstName'}</span>
391 </div>
392 <div class="form-group">
393 <label for="inputManageLastName">{lang key='orderForm.lastName'}</label>
394 <input id="inputManageLastName" type="text" autocomplete="off" class="form-control required" name="last">
395 <span class="field-error-msg">{lang key='ox.required.lastName'}</span>
396 </div>
397 </div>
398 <div class="modal-footer panel-footer">
399 <div class="pull-left loader hidden">
400 <i class="fas fa-sync-alt fa-spin"></i>
401 {lang key='loading'}
402 </div>
403 <button type="button" class="btn btn-default" data-dismiss="modal">
404 {lang key='close'}
405 </button>
406 <button type="button" class="btn btn-primary ox-submit-button">
407 {lang key='clientareasavechanges'}
408 </button>
409 </div>
410 </div>
411 </div>
412 </div>
413</form>
414<form id="frmOxSetPassword" action="{$setPasswordUrl}" method="post">
415 <div class="modal fade" id="modalSetPassword">
416 <input type="hidden" value="" name="account">
417 <div class="modal-dialog">
418 <div class="modal-content panel-primary">
419 <div class="modal-header panel-heading">
420 <button type="button" class="close" data-dismiss="modal" aria-label="{lang key='close'}"><span aria-hidden="true">&times;</span></button>
421 <h4 class="modal-title" id="modalSetPasswordTitle">
422 {lang key='ox.setPasswordFor'}
423 </h4>
424 </div>
425 <div class="modal-body panel-body" id="modalSetPasswordBody">
426 <div class="alert alert-danger modal-error hidden">
427 <i class="fas fa-times fa-fw"></i>
428 <span></span>
429 </div>
430 <div class="form-group">
431 <label for="inputChangePassword">{lang key='clientareapassword'}</label>
432 <div class="input-group">
433 <input type="password" class="form-control required" name="password" id="inputChangePassword" data-error-threshold="{$pwStrengthErrorThreshold}" data-warning-threshold="{$pwStrengthWarningThreshold}" placeholder="{lang key="loginpassword"}" autocomplete="off" />
434 <span class="input-group-btn">
435 <button type="button" class="btn btn-default generate-password" data-targetfields="inputChangePassword,inputChangePasswordConfirm">
436 {lang key="generatePassword.btnShort"}
437 </button>
438 </span>
439 </div>
440
441 <div class="password-strength-meter">
442 <div class="progress" style="height: 10px; margin-top: 10px">
443 <div class="progress-bar progress-bar-success progress-bar-striped" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" id="passwordStrengthMeterBar">
444 </div>
445 </div>
446 <p class="text-center small text-muted" id="passwordStrengthTextLabel">{lang key="pwstrength"}: {lang key="pwstrengthenter"}</p>
447 </div>
448 <span class="field-error-msg">{lang key='ox.required.password'}</span>
449 </div>
450 <div class="form-group">
451 <label for="inputChangePasswordConfirm">{lang key='clientareaconfirmpassword'}</label>
452 <input id="inputChangePasswordConfirm" type="password" autocomplete="off" class="form-control required match" data-match-field="inputChangePassword" name="password2">
453 <span class="field-error-msg">{lang key='ox.required.passwordMatch'}</span>
454 </div>
455 </div>
456 <div class="modal-footer panel-footer">
457 <div class="pull-left loader hidden">
458 <i class="fas fa-sync-alt fa-spin"></i>
459 {lang key='loading'}
460 </div>
461 <button type="button" class="btn btn-default" data-dismiss="modal">
462 {lang key='close'}
463 </button>
464 <button type="button" class="btn btn-primary ox-submit-button">
465 {lang key='ox.setPassword'}
466 </button>
467 </div>
468 </div>
469 </div>
470 </div>
471</form>
472<form id="frmOxDeleteAccount" action="{$deleteAccountUrl}" method="post">
473 <div class="modal fade" id="modalDeleteAccount">
474 <input type="hidden" value="" name="account">
475 <div class="modal-dialog">
476 <div class="modal-content panel-primary">
477 <div class="modal-header panel-heading">
478 <button type="button" class="close" data-dismiss="modal" aria-label="{lang key='close'}"><span aria-hidden="true">&times;</span></button>
479 <h4 class="modal-title" id="modalDeleteAccountTitle">
480 {lang key='ox.deleteAccount'}
481 </h4>
482 </div>
483 <div class="modal-body panel-body" id="modalDeleteAccountBody">
484 <div class="alert alert-danger modal-error hidden">
485 <i class="fas fa-times fa-fw"></i>
486 <span></span>
487 </div>
488 <span class="delete-question" aria-hidden="true">{lang key='ox.deleteAccountQuestion'}</span>
489 <span class="delete-aliases-question" aria-hidden="true">{lang key='ox.deleteAccountWithAliasesQuestion'}</span>
490 </div>
491 <div class="modal-footer panel-footer">
492 <div class="pull-left loader hidden">
493 <i class="fas fa-sync-alt fa-spin"></i>
494 {lang key='loading'}
495 </div>
496 <button type="button" class="btn btn-default" data-dismiss="modal">
497 {lang key='close'}
498 </button>
499 <button type="button" class="btn btn-danger ox-submit-button" id="btnDoDelete">
500 {lang key='ox.delete'}
501 </button>
502 </div>
503 </div>
504 </div>
505 </div>
506</form>
507<form id="frmOxDeleteAlias" action="{$modifyAliasesUrl}" method="post">
508 <div class="modal fade" id="modalDeleteAlias">
509 <input type="hidden" value="" name="aliasAction">
510 <input type="hidden" value="" name="account">
511 <input type="hidden" value="" name="alias">
512 <input type="hidden" value="" name="aliases">
513 <div class="modal-dialog">
514 <div class="modal-content">
515 <div class="modal-header panel-header bg-primary text-light">
516 <button type="button" class="close" data-dismiss="modal" aria-label="{lang key='close'}"><span aria-hidden="true">&times;</span></button>
517 <h4 class="modal-title" id="modalDeleteAccountTitle">
518 {lang key='ox.alias.deleteTitle' domain=$domain}
519 </h4>
520 </div>
521 <div class="modal-body panel-body" id="modalDeleteAccountBody">
522 <div class="alert alert-danger modal-error hidden">
523 <i class="fas fa-times fa-fw"></i>
524 <span></span>
525 </div>
526 {lang key='ox.alias.deleteQuestion'}
527 </div>
528 <div class="modal-footer panel-footer">
529 <div class="pull-left loader hidden">
530 <i class="fas fa-sync-alt fa-spin"></i>
531 {lang key='loading'}
532 </div>
533 <button type="button" class="btn btn-default" data-dismiss="modal">
534 {lang key='close'}
535 </button>
536 <button type="button" class="btn btn-danger ox-submit-button" id="btnDoDelete">
537 {lang key='ox.delete'}
538 </button>
539 </div>
540 </div>
541 </div>
542 </div>
543</form>
544
545<script src="{$BASE_PATH_JS}/PasswordStrength.js"></script>
546<script>
547 function loadAccounts(force) {
548 var trLoading = jQuery('tr.loading'),
549 divError = jQuery('#oxLoadError'),
550 trNoAccounts = jQuery('tr.no-accounts');
551
552 force = force || 0;
553
554 if (divError.is(':visible')) {
555 divError.addClass('hidden');
556 }
557
558 jQuery('#btnRefresh').addClass('disabled')
559 .prop('disabled', 'disabled')
560 .find('i')
561 .addClass('fa-spin');
562
563 clearAccounts();
564 clearAliases();
565 trNoAccounts.addClass('hidden');
566 if (trLoading.not(':visible')) {
567 trLoading.removeClass('hidden');
568 }
569 WHMCS.http.jqClient.jsonPost({
570 url: '{$listAccountsUrl}',
571 data: {
572 token: csrfToken,
573 force: force
574 },
575 success: function(data) {
576 if (data.failedMessage) {
577 jQuery('#oxLoadError').text(data.failedMessage).removeClass('hidden');
578 } else {
579 if (typeof data.accounts.length === "undefined" || data.accounts.length === 0) {
580 trNoAccounts.removeClass('hidden');
581 } else {
582 jQuery.each(data.accounts, function(index, account) {
583 addAccountToTable(account);
584 addAliasesToTable(account);
585 updateAliasesDisplay(account.id);
586 });
587 }
588 }
589 },
590 always: function() {
591 trLoading.addClass('hidden');
592 updateAccountsDisplay();
593 jQuery('#btnRefresh').removeClass('disabled').prop('disabled', false)
594 .find('i').removeClass('fa-spin');
595 }
596 });
597 }
598
599 function addAccountToTable(data) {
600 var table = jQuery('table.ox-table-accounts'),
601 clone = jQuery('tbody.cloneAccountsBody').clone();
602
603 clone.attr('id', '');
604 clone.find('.account')
605 .text(data.username);
606 clone.find('.limit')
607 .text(data.quota);
608 clone.attr('data-account-id', data.id)
609 .attr('data-first-name', data.first_name)
610 .attr('data-last-name', data.last_name)
611 .attr('data-display-name', data.display_name)
612 .attr('data-account', data.username + '@{$domain}');
613 clone.addClass('account-entry').removeClass('cloneAccountsBody hidden');
614 table.append(clone);
615 }
616
617 function addAliasesToTable(data) {
618 var table = jQuery('table.ox-table-accounts'),
619 cloneTbody = jQuery('tbody.cloneAliasesBody').clone();
620
621 if (typeof data.aliases !== 'undefined' && data.aliases.length > 0) {
622 data.aliases.forEach(function(alias) {
623 var isPrimary = false;
624 if (data.username.localeCompare(alias, 'en', { sensitivity: 'base' }) === 0) {
625 isPrimary = true;
626 }
627 addAliasTr(alias, cloneTbody.find('table'), isPrimary);
628 })
629 }
630
631 cloneTbody.attr('data-account-id', data.id).attr('id', 'tbodyAlias' + data.id);
632 cloneTbody.removeClass('cloneAliasesBody hidden').addClass('aliases-body hidden');
633 table.append(cloneTbody);
634 }
635
636 function addAliasTr(alias, cloneTbody, isPrimary = false) {
637 var cloneTr = jQuery('tr.cloneAliasRow').clone();
638
639 cloneTr.find('.alias')
640 .text(alias);
641 cloneTr.attr('data-alias', alias);
642 cloneTr.addClass('alias-entry').removeClass('cloneAliasRow');
643 if (isPrimary === false) {
644 cloneTr.removeClass('hidden');
645 }
646 cloneTbody.prepend(cloneTr);
647 }
648
649 function clearAccounts() {
650 jQuery('.ox-table-accounts tbody.account-entry').remove();
651 }
652
653 function clearAliases() {
654 jQuery('.ox-table-accounts tbody.aliases-body').remove();
655 }
656
657 function updateAccountsDisplay() {
658 var trNoAccounts = jQuery('table.ox-table-accounts tbody tr.no-accounts'),
659 accountsCount = jQuery('#accountCount').find('.number');
660 var count = jQuery('table.ox-table-accounts tbody.account-entry').length;
661 if (count == 0) {
662 trNoAccounts.removeClass('hidden');
663 } else {
664 trNoAccounts.addClass('hidden');
665 }
666 accountsCount.text(count);
667 }
668
669 function updateAliasesDisplay(accountId) {
670 var aliasesCount = jQuery('tbody.account-entry[data-account-id="' + accountId + '"] span.alias-count');
671 count = jQuery('tbody.aliases-body[data-account-id="' + accountId + '"] tr.alias-entry')
672 .not('.hidden')
673 .length;
674 aliasesCount.text(count);
675 }
676
677 function loadConfiguration(force) {
678 var tabNames = ['Usage'];
679 var tabs = [];
680 tabNames.forEach(function(tabName) {
681 var tabSpec = {
682 'panel': jQuery('#tablePanel' + tabName),
683 'header': jQuery('#tablePanel' + tabName + 'Head'),
684 };
685 tabs.push(tabSpec);
686 if (tabSpec.header.find('tr.loading').not(':visible')) {
687 tabSpec.header.find('tr.loading').removeClass('hidden');
688 }
689 });
690
691 force = force || 0;
692 WHMCS.http.jqClient.jsonPost({
693 url: '{$configurationUrl}',
694 data: {
695 force: force,
696 token: csrfToken
697 },
698 success: function(data) {
699 var error = '{lang|addslashes key="unavailable"}';
700 if (data.settings) {
701 jQuery('.incoming-hostname').text(data.settings.incoming.hostname);
702 jQuery('.incoming-port').text(data.settings.incoming.port);
703 jQuery('.pop-hostname').text(data.settings.pop.hostname);
704 jQuery('.pop-port').text(data.settings.pop.port);
705 jQuery('.outgoing-hostname').text(data.settings.outgoing.hostname);
706 jQuery('.outgoing-port').text(data.settings.outgoing.port);
707 jQuery('.calendar-server').text(data.settings.calendar.hostname);
708 } else {
709 jQuery('.incoming-hostname').text(error);
710 jQuery('.incoming-port').text(error);
711 jQuery('.pop-hostname').text(error);
712 jQuery('.pop-port').text(error);
713 jQuery('.outgoing-hostname').text(error);
714 jQuery('.outgoing-port').text(error);
715 jQuery('.calendar-server').text(error);
716 }
717 if (data.usage) {
718 var tabSpec = tabs[tabNames.indexOf('Usage')];
719 tabSpec.panel.find('tr').remove();
720 jQuery.each(data.usage, function (index, value) {
721 tabSpec.panel.append(
722 '<tr><td>' + value + '</td></tr>'
723 );
724 });
725 }
726 if (data.migration_tool) {
727 jQuery('.migration-url').attr('href', data.migration_tool.url);
728 jQuery('#migration, #migrationNav').removeClass('hidden');
729 }
730 },
731 always: function() {
732 tabs.forEach(function(tabSpec) {
733 tabSpec.header.find('tr.loading').addClass('hidden');
734 });
735 }
736 });
737 }
738 jQuery(document).on('ready', function() {
739 loadAccounts();
740 loadConfiguration();
741 window.langPasswordStrength = "{lang key="pwstrength"}";
742 window.langPasswordWeak = "{lang key="pwstrengthweak"}";
743 window.langPasswordModerate = "{lang key="pwstrengthmoderate"}";
744 window.langPasswordStrong = "{lang key="pwstrengthstrong"}";
745
746 jQuery("#inputPassword,#inputChangePassword").keyup(registerFormPasswordStrengthFeedback);
747 jQuery('button.btn-add').width(function() {
748 return jQuery(this).outerWidth(true);
749 }).find('span.loading').toggleClass('hidden loading');
750 jQuery('#modalAddAccount,#modalSetPassword').on('shown.bs.modal', function() {
751 jQuery('.modal-backdrop.fade.in').css('zIndex', 1030);
752 jQuery(this).css('zIndex', 1035);
753 });
754 jQuery(document)
755 .on('click', '#btnRefresh', function() {
756 jQuery(this).addClass('disabled').prop('disabled', true);
757 loadAccounts(true);
758 loadConfiguration(true);
759 })
760 .on('click', '#btnAddAccount', function() {
761 jQuery('#modalAddAccount').modal('show');
762 })
763 .on('click', 'tbody.account-entry', function() {
764 var accountId = jQuery(this).data('account-id'),
765 aliasesBody = jQuery('#tbodyAlias' + accountId);
766 if (aliasesBody.is(':visible')) {
767 jQuery(this).find('i.fa-chevron-right').attr(
768 'style',
769 'transform: rotate(0deg); transition: .1s transform ease-in-out;',
770 );
771 aliasesBody.addClass('hidden');
772 } else {
773 jQuery(this).find('i.fa-chevron-right').attr(
774 'style',
775 'transform: rotate(90deg); transition: .1s transform ease-in-out;',
776 );
777 aliasesBody.removeClass('hidden');
778 }
779 })
780 .on('click', '.manage-account', function(e) {
781 var tbody = jQuery(this).closest('tbody'),
782 accountId = tbody.data('account-id'),
783 account = tbody.data('account'),
784 modalManageAccount = jQuery('#modalManageAccount');
785
786 e.stopPropagation();
787 modalManageAccount.find('input[name="account"]').val(accountId);
788 modalManageAccount.find('span.email').text(account);
789 jQuery('#inputManageDisplayName').val(tbody.attr('data-display-name'));
790 jQuery('#inputManageFirstName').val(tbody.attr('data-first-name'));
791 jQuery('#inputManageLastName').val(tbody.attr('data-last-name'));
792 modalManageAccount.modal('show');
793 })
794 .on('click', '.set-ox-password', function(e) {
795 var accountId = jQuery(this).closest('tbody').data('account-id'),
796 account = jQuery(this).closest('tbody').data('account'),
797 modalSetPassword = jQuery('#modalSetPassword');
798
799 e.stopPropagation();
800 modalSetPassword.find('input[name="account"]').val(accountId);
801 modalSetPassword.find('span.email').text(account);
802 modalSetPassword.modal('show');
803 })
804 .on('click', '.ox-delete', function(e) {
805 var accountId = jQuery(this).closest('tbody.account-entry').data('account-id'),
806 account = jQuery(this).closest('tbody.account-entry').data('account'),
807 modalDeleteAccount = jQuery('#modalDeleteAccount'),
808 aliasCount = jQuery(this).closest('tbody.account-entry').find('span.alias-count').text(),
809 deleteAliasesSpan = jQuery('span.delete-aliases-question'),
810 deleteAccountSpan = jQuery('span.delete-question');
811
812 deleteAccountSpan.addClass('hidden');
813 deleteAliasesSpan.addClass('hidden');
814 if (aliasCount > 0) {
815 deleteAliasesSpan.removeClass('hidden');
816 } else {
817 deleteAccountSpan.removeClass('hidden');
818 }
819
820 e.stopPropagation();
821 modalDeleteAccount.find('input[name="account"]').val(accountId);
822 modalDeleteAccount.find('span.count').text(aliasCount);
823 modalDeleteAccount.find('span.email').text(account);
824 modalDeleteAccount.modal('show');
825 })
826 .on('click', '.ox-create-alias', function() {
827 var element = jQuery(this),
828 oxError = jQuery('#oxLoadError'),
829 oxSuccess = jQuery('#oxSuccess'),
830 accountId = element.closest('tbody.aliases-body').data('account-id'),
831 aliasTableTbody = element.closest('tbody'),
832 alias = element.closest('tr.create-alias')
833 .find('input[name="alias"]').val(),
834 aliases = element.closest('tbody.aliases-body')
835 .find('tr.alias-entry')
836 .map(function(index, element) {
837 return jQuery(element).data('alias') + '@{$domain}';
838 }).get();
839
840 element.css('min-width', element.outerWidth());
841 element.find('span.create-string').addClass('hidden');
842 element.attr('disabled', 'disabled').addClass('disabled');
843 element.find('span.loader').removeClass('hidden');
844
845 if (typeof alias === 'undefined' && alias.length == 0) {
846 return false;
847 }
848
849 aliases.push(alias + '@{$domain}');
850
851 WHMCS.http.jqClient.jsonPost({
852 url: '{$modifyAliasesUrl}',
853 data: {
854 token: csrfToken,
855 aliasAction: 'create',
856 account: accountId,
857 aliases: JSON.stringify(aliases),
858 },
859 success: function(data) {
860 oxError.addClass('hidden').find('span').text('');
861 oxSuccess.addClass('hidden').find('span').text('');
862
863 if (data.success === true) {
864 oxSuccess.find('span').text(data.successMessage);
865 oxSuccess.removeClass('hidden');
866 addAliasTr(
867 alias,
868 aliasTableTbody
869 );
870 element.closest('tr.create-alias')
871 .find('input[name="alias"]')
872 .val('');
873 } else {
874 oxError.find('span').text(data.failedMessage);
875 oxError.removeClass('hidden');
876 }
877 },
878 always: function() {
879 element.find('span.loader').addClass('hidden');
880 element.find('span.create-string').removeClass('hidden');
881 element.removeAttr('disabled').removeClass('disabled');
882 updateAliasesDisplay(accountId);
883 }
884 });
885 })
886 .on('click', '.ox-delete-alias', function() {
887 var accountId = jQuery(this).closest('tbody.aliases-body').data('account-id'),
888 alias = jQuery(this).closest('tr.alias-entry').data('alias'),
889 aliases = jQuery(this).closest('tr.alias-entry')
890 .siblings('tr.alias-entry')
891 .map(function(index, element) {
892 return jQuery(element).data('alias') + '@{$domain}';
893 }).get(),
894 modalDeleteAlias = jQuery('#modalDeleteAlias');
895
896 modalDeleteAlias.find('.modal-error').addClass('hidden').text(''),
897 modalDeleteAlias.find('input[name="aliasAction"]').val('delete');
898 modalDeleteAlias.find('input[name="account"]').val(accountId);
899 modalDeleteAlias.find('input[name="alias"]').val(alias);
900 modalDeleteAlias.find('input[name="aliases"]').val(JSON.stringify(aliases));
901 modalDeleteAlias.find('span.alias').text(alias);
902 modalDeleteAlias.modal('show');
903 })
904 .on('click', '.ox-submit-button', function() {
905 var frm = jQuery(this).closest('form'),
906 formId = frm.attr('id'),
907 modal = frm.find('div.modal'),
908 formData = frm.serialize(),
909 accountId = frm.find('input[name="account"]').val(),
910 oxError = modal.find('.modal-error'),
911 oxLoadError = jQuery('#oxLoadError'),
912 oxSuccess = jQuery('#oxSuccess'),
913 err = false;
914
915 frm.find('.form-group').removeClass('has-error');
916 frm.find('.field-error-msg').addClass('hidden');
917
918 frm.find('.required').each(function() {
919 if (jQuery(this).val() === '') {
920 if (jQuery(this).hasClass('match')) {
921 jQuery(this).setInputError("{lang key='ox.required.passwordMatchMissing'}");
922 }
923 jQuery(this).showInputError();
924 err = true;
925 }
926 });
927
928 frm.find('.match').each(function() {
929 var matchInput = jQuery(this).data('match-field');
930 if (jQuery('#' + matchInput).val() !== jQuery(this).val()) {
931 jQuery(this).setInputError("{lang key='ox.required.passwordMatch'}").showInputError();
932 err = true;
933 }
934 });
935 if (formId === 'frmOxAddAccount') {
936 var verify = jQuery('#inputConfirmPassword');
937 if (jQuery('#inputPassword').val() !== verify.val()) {
938 verify.showInputError();
939 err = true;
940 }
941 }
942 if (formId === 'frmOxSetPassword') {
943 var verify2 = jQuery('#inputChangePasswordConfirm');
944 if (jQuery('#inputChangePassword').val() !== verify2.val()) {
945 verify2.showInputError();
946 err = true;
947 }
948 }
949 if (!err) {
950 modal.find('.loader').removeClass('hidden');
951 WHMCS.http.jqClient.jsonPost({
952 url: frm.attr('action'),
953 data: formData,
954 success: function(data) {
955 oxError.addClass('hidden').find('span').text('');
956 oxLoadError.addClass('hidden');
957 oxSuccess.addClass('hidden');
958 if (data.success === true) {
959 var tbody = jQuery('tbody[data-account-id="' + accountId + '"]');
960 oxSuccess.find('span').text(data.successMessage);
961 oxSuccess.removeClass('hidden');
962 switch (formId) {
963 case 'frmOxDeleteAccount':
964 tbody.slideUp().remove();
965 break;
966 case 'frmOxAddAccount':
967 data.aliases = [data.username];
968 addAccountToTable(data);
969 addAliasesToTable(data);
970 updateAliasesDisplay(data.id);
971 break;
972 case 'frmOxManageAccount':
973 tbody.attr('data-display-name', data.display_name);
974 tbody.attr('data-first-name', data.first_name);
975 tbody.attr('data-last-name', data.last_name);
976 break;
977 case 'frmOxDeleteAlias':
978 var alias = frm.find('input[name="alias"]').val(),
979 tr = jQuery('tr.alias-entry[data-alias="' + alias + '"]');
980 tr.slideUp().remove();
981 break;
982 }
983 frm.find('input').not('[name="token"]').each(function() {
984 jQuery(this).val('');
985 });
986 modal.modal('hide');
987 } else {
988 oxError.find('span').text(data.failedMessage);
989 oxError.removeClass('hidden');
990 }
991 },
992 always: function() {
993 updateAccountsDisplay();
994 updateAliasesDisplay(accountId);
995 modal.find('.loader').addClass('hidden');
996 }
997 });
998 }
999 });
1000 });
1001</script>
1002