]> git.proxmox.com Git - pmg-gui.git/blob - js/Utils.js
mail proxy: networks: consitent add/edit/remove button & modernization
[pmg-gui.git] / js / Utils.js
1 Ext.ns('PMG');
2
3 console.log("Starting PMG Manager");
4
5
6 Ext.define('PMG.Utils', {
7 singleton: true,
8
9 // this singleton contains miscellaneous utilities
10
11 // use in panels with object spread (...) operator, for example:
12 // ...PMG.Utils.onlineHelpTool('sysadmin_certificate_management'),
13 onlineHelpTool: function(blockid) {
14 let info = Proxmox.Utils.get_help_info(blockid);
15 if (info === undefined) {
16 info = Proxmox.Utils.get_help_info('pmg_documentation_index');
17 if (info === undefined) {
18 throw "get_help_info failed"; // should not happen
19 }
20 }
21
22 let docsURI = window.location.origin + info.link;
23 let title = info.title || gettext('Help');
24 if (info.subtitle) {
25 title += ' - ' + info.subtitle;
26 }
27 return {
28 tools: [
29 {
30 type: 'help',
31 tooltip: title,
32 handler: () => window.open(docsURI),
33 },
34 ],
35 };
36 },
37
38 senderText: gettext('Sender'),
39 receiverText: gettext('Receiver'),
40 scoreText: gettext('Score'),
41
42 user_role_text: {
43 root: gettext('Superuser'),
44 admin: gettext('Administrator'),
45 helpdesk: gettext('Help Desk'),
46 qmanager: gettext('Quarantine Manager'),
47 audit: gettext('Auditor'),
48 },
49
50 format_user_role: function(role) {
51 return PMG.Utils.user_role_text[role] || role;
52 },
53
54 oclass_text: {
55 who: gettext('Who Objects'),
56 what: gettext('What Objects'),
57 when: gettext('When Objects'),
58 action: gettext('Action Objects'),
59 from: gettext('From'),
60 to: gettext('To'),
61 },
62
63 oclass_icon: {
64 who: '<span class="fa fa-fw fa-user-circle"></span> ',
65 what: '<span class="fa fa-fw fa-cube"></span> ',
66 when: '<span class="fa fa-fw fa-clock-o"></span> ',
67 action: '<span class="fa fa-fw fa-flag"></span> ',
68 from: '<span class="fa fa-fw fa-user-circle"></span> ',
69 to: '<span class="fa fa-fw fa-user-circle"></span> ',
70 },
71
72 mail_status_map: {
73 2: 'delivered',
74 4: 'deferred',
75 5: 'bounced',
76 N: 'rejected',
77 G: 'greylisted',
78 A: 'accepted',
79 B: 'blocked',
80 Q: 'quarantine',
81 },
82
83 icon_status_map_class: {
84 2: 'check-circle',
85 4: 'clock-o',
86 5: 'mail-reply',
87 N: 'times-circle',
88 G: 'list',
89 A: 'check',
90 B: 'ban',
91 Q: 'cube',
92 },
93
94 icon_status_map_color: {
95 2: 'green',
96 5: 'gray',
97 A: 'green',
98 B: 'red',
99 },
100
101 format_status_icon: function(status) {
102 var icon = PMG.Utils.icon_status_map_class[status] || 'question-circle';
103 var color = PMG.Utils.icon_status_map_color[status] || '';
104 return '<i class="fa fa-' + icon + ' ' + color + '"></i> ';
105 },
106
107 format_oclass: function(oclass) {
108 var icon = PMG.Utils.oclass_icon[oclass] || '';
109 var text = PMG.Utils.oclass_text[oclass] || oclass;
110 return icon + text;
111 },
112
113 rule_direction_text: {
114 0: gettext('In'),
115 1: gettext('Out'),
116 2: gettext('In & Out'),
117 },
118
119 rule_direction_icon: {
120 0: '<span class="fa fa-fw fa-long-arrow-left"></span> ',
121 1: '<span class="fa fa-fw fa-long-arrow-right"></span> ',
122 2: '<span class="fa fa-fw fa-exchange"></span> ',
123 },
124
125 format_rule_direction: function(dir) {
126 var icon = PMG.Utils.rule_direction_icon[dir] || '';
127 var text = PMG.Utils.rule_direction_text[dir] || dir;
128 return icon + text;
129 },
130
131 format_otype: function(otype) {
132 let editor = PMG.Utils.object_editors[otype];
133 let iconCls = 'fa fa-question-circle';
134 if (editor) {
135 return `<span class="fa-fw ${editor.iconCls || iconCls}"></span> ${editor.subject}`;
136 }
137 return `<span class="fa-fw ${iconCls}"></span> unknown`;
138 },
139
140 format_ldap_protocol: function(p) {
141 if (p === undefined) { return 'LDAP'; }
142 if (p === 'ldap') { return 'LDAP'; }
143 if (p === 'ldaps') { return 'LDAPS'; }
144 if (p === 'ldap+starttls') { return 'LDAP+STARTTLS'; }
145 return 'unknown';
146 },
147
148 convert_field_to_per_min: function(value, record) {
149 return value / (record.data.timespan / 60);
150 },
151
152 object_editors: {
153 1000: {
154 onlineHelp: 'pmg_mailfilter_regex',
155 iconCls: 'fa fa-filter',
156 xtype: 'proxmoxWindowEdit',
157 subdir: 'regex',
158 subject: gettext("Regular Expression"),
159 width: 400,
160 items: [
161 {
162 xtype: 'textfield',
163 name: 'regex',
164 reference: 'regex',
165 fieldLabel: gettext("Regex"),
166 },
167 {
168 xtype: 'pmgRegexTester',
169 fieldLabel: gettext('Test String'),
170 wholeMatch: true,
171 regexFieldReference: 'regex',
172 },
173 ],
174 },
175 1005: {
176 onlineHelp: 'pmgconfig_ldap',
177 iconCls: 'fa fa-users',
178 xtype: 'pmgLDAPGroupEditor',
179 subdir: 'ldap',
180 subject: gettext("LDAP Group"),
181 },
182 1006: {
183 onlineHelp: 'pmgconfig_ldap',
184 iconCls: 'fa fa-user',
185 xtype: 'pmgLDAPUserEditor',
186 subdir: 'ldapuser',
187 subject: gettext("LDAP User"),
188 },
189 1009: {
190 onlineHelp: 'pmg_mailfilter_regex',
191 iconCls: 'fa fa-filter',
192 xtype: 'proxmoxWindowEdit',
193 subdir: 'receiver_regex',
194 subject: gettext("Regular Expression"),
195 receivertest: true,
196 width: 400,
197 items: [
198 {
199 xtype: 'textfield',
200 name: 'regex',
201 fieldLabel: gettext("Regex"),
202 },
203 ],
204 },
205 1001: {
206 onlineHelp: 'pmg_mailfilter_who',
207 iconCls: 'fa fa-envelope-o',
208 xtype: 'proxmoxWindowEdit',
209 subdir: 'email',
210 subject: gettext("E-Mail"),
211 width: 400,
212 items: [
213 {
214 xtype: 'textfield',
215 name: 'email',
216 fieldLabel: gettext("E-Mail"),
217 },
218 ],
219 },
220 1007: {
221 onlineHelp: 'pmg_mailfilter_who',
222 iconCls: 'fa fa-envelope-o',
223 xtype: 'proxmoxWindowEdit',
224 subdir: 'receiver',
225 subject: gettext("E-Mail"),
226 receivertest: true,
227 width: 400,
228 items: [
229 {
230 xtype: 'textfield',
231 name: 'email',
232 fieldLabel: gettext("E-Mail"),
233 },
234 ],
235 },
236 1002: {
237 onlineHelp: 'pmg_mailfilter_who',
238 iconCls: 'fa fa-globe',
239 xtype: 'proxmoxWindowEdit',
240 subdir: 'domain',
241 subject: gettext("Domain"),
242 width: 400,
243 items: [
244 {
245 xtype: 'textfield',
246 name: 'domain',
247 fieldLabel: gettext("Domain"),
248 },
249 ],
250 },
251 1008: {
252 onlineHelp: 'pmg_mailfilter_who',
253 iconCls: 'fa fa-globe',
254 xtype: 'proxmoxWindowEdit',
255 subdir: 'receiver_domain',
256 subject: gettext("Domain"),
257 receivertest: true,
258 width: 400,
259 items: [
260 {
261 xtype: 'textfield',
262 name: 'domain',
263 fieldLabel: gettext("Domain"),
264 },
265 ],
266 },
267 1003: {
268 onlineHelp: 'pmg_mailfilter_who',
269 iconCls: 'fa fa-globe',
270 xtype: 'proxmoxWindowEdit',
271 subdir: 'ip',
272 subject: gettext("IP Address"),
273 width: 400,
274 items: [
275 {
276 xtype: 'textfield',
277 name: 'ip',
278 fieldLabel: gettext("IP Address"),
279 },
280 ],
281 },
282 1004: {
283 onlineHelp: 'pmg_mailfilter_who',
284 iconCls: 'fa fa-globe',
285 xtype: 'proxmoxWindowEdit',
286 subdir: 'network',
287 subject: gettext("IP Network"),
288 width: 400,
289 items: [
290 {
291 xtype: 'textfield',
292 name: 'cidr',
293 fieldLabel: gettext("IP Network"),
294 },
295 ],
296 },
297 2000: {
298 onlineHelp: 'pmg_mailfilter_when',
299 iconCls: 'fa fa-clock-o',
300 xtype: 'proxmoxWindowEdit',
301 subdir: 'timeframe',
302 subject: gettext("TimeFrame"),
303 items: [
304 {
305 xtype: 'timefield',
306 name: 'start',
307 format: 'H:i',
308 fieldLabel: gettext("Start Time"),
309 },
310 {
311 xtype: 'timefield',
312 name: 'end',
313 format: 'H:i',
314 fieldLabel: gettext("End Time"),
315 },
316 ],
317 },
318 3000: {
319 onlineHelp: 'pmg_mailfilter_what',
320 iconCls: 'fa fa-bullhorn',
321 xtype: 'proxmoxWindowEdit',
322 subdir: 'spamfilter',
323 subject: gettext('Spam Filter'),
324 items: [
325 {
326 xtype: 'proxmoxintegerfield',
327 name: 'spamlevel',
328 allowBlank: false,
329 minValue: 0,
330 fieldLabel: gettext('Level'),
331 },
332 ],
333 },
334 3001: {
335 onlineHelp: 'pmg_mailfilter_what',
336 iconCls: 'fa fa-bug',
337 xtype: 'proxmoxWindowEdit',
338 subdir: 'virusfilter',
339 subject: gettext('Virus Filter'),
340 uneditable: true,
341 // there are no parameters to give, so we simply submit it
342 listeners: {
343 show: function(win) {
344 win.submit();
345 },
346 },
347 },
348 3002: {
349 onlineHelp: 'pmg_mailfilter_regex',
350 iconCls: 'fa fa-code',
351 xtype: 'proxmoxWindowEdit',
352 subdir: 'matchfield',
353 subject: gettext('Match Field'),
354 width: 400,
355 items: [
356 {
357 xtype: 'textfield',
358 name: 'field',
359 allowBlank: false,
360 fieldLabel: gettext('Field'),
361 },
362 {
363 xtype: 'textfield',
364 name: 'value',
365 reference: 'value',
366 allowBlank: false,
367 fieldLabel: gettext('Value'),
368 },
369 {
370 xtype: 'pmgRegexTester',
371 fieldLabel: gettext('Test String'),
372 regexFieldReference: 'value',
373 },
374 ],
375 },
376 3003: {
377 onlineHelp: 'pmg_mailfilter_what',
378 iconCls: 'fa fa-file-image-o',
379 xtype: 'proxmoxWindowEdit',
380 subdir: 'contenttype',
381 width: 400,
382 subject: gettext('Content Type Filter'),
383 items: [
384 {
385 xtype: 'combobox',
386 displayField: 'text',
387 valueField: 'mimetype',
388 name: 'contenttype',
389 editable: true,
390 queryMode: 'local',
391 store: {
392 autoLoad: true,
393 proxy: {
394 type: 'proxmox',
395 url: '/api2/json/config/mimetypes',
396 },
397 },
398 fieldLabel: gettext('Content Type'),
399 anyMatch: true,
400 matchFieldWidth: false,
401 listeners: {
402 change: function(cb, value) {
403 var me = this;
404 me.up().down('displayfield').setValue(value);
405 },
406 },
407 },
408 {
409 xtype: 'displayfield',
410 fieldLabel: gettext('Value'),
411 allowBlank: false,
412 reset: Ext.emptyFn,
413 },
414 ],
415 },
416 3004: {
417 onlineHelp: 'pmg_mailfilter_regex',
418 iconCls: 'fa fa-file-o',
419 xtype: 'proxmoxWindowEdit',
420 subdir: 'filenamefilter',
421 width: 400,
422 subject: gettext('Match Filename'),
423 items: [
424 {
425 xtype: 'textfield',
426 name: 'filename',
427 reference: 'filename',
428 fieldLabel: gettext('Filename'),
429 allowBlank: false,
430 },
431 {
432 xtype: 'pmgRegexTester',
433 fieldLabel: gettext('Test String'),
434 wholeMatch: true,
435 regexFieldReference: 'filename',
436 },
437 ],
438 },
439 3005: {
440 onlineHelp: 'pmg_mailfilter_what',
441 iconCls: 'fa fa-file-archive-o',
442 xtype: 'proxmoxWindowEdit',
443 subdir: 'archivefilter',
444 width: 400,
445 subject: gettext('Archive Filter'),
446 items: [
447 {
448 xtype: 'combobox',
449 displayField: 'text',
450 valueField: 'mimetype',
451 name: 'contenttype',
452 editable: true,
453 queryMode: 'local',
454 store: {
455 autoLoad: true,
456 proxy: {
457 type: 'proxmox',
458 url: '/api2/json/config/mimetypes',
459 },
460 },
461 fieldLabel: gettext('Content Type'),
462 anyMatch: true,
463 matchFieldWidth: false,
464 listeners: {
465 change: function(cb, value) {
466 var me = this;
467 me.up().down('displayfield').setValue(value);
468 },
469 },
470 },
471 {
472 xtype: 'displayfield',
473 fieldLabel: gettext('Value'),
474 allowBlank: false,
475 reset: Ext.emptyFn,
476 },
477 ],
478 },
479 3006: {
480 onlineHelp: 'pmg_mailfilter_regex',
481 iconCls: 'fa fa-file-archive-o',
482 xtype: 'proxmoxWindowEdit',
483 subdir: 'archivefilenamefilter',
484 width: 400,
485 subject: gettext('Match Archive Filename'),
486 items: [
487 {
488 xtype: 'textfield',
489 name: 'filename',
490 reference: 'filename',
491 fieldLabel: gettext('Filename'),
492 allowBlank: false,
493 },
494 {
495 xtype: 'pmgRegexTester',
496 fieldLabel: gettext('Test String'),
497 wholeMatch: true,
498 regexFieldReference: 'filename',
499 },
500 ],
501 },
502 4002: {
503 onlineHelp: 'pmg_mailfilter_action',
504 xtype: 'proxmoxWindowEdit',
505 subdir: 'notification',
506 subject: gettext('Notification'),
507 width: 400,
508 items: [
509 {
510 xtype: 'textfield',
511 name: 'name',
512 allowBlank: false,
513 fieldLabel: gettext('Name'),
514 },
515 {
516 xtype: 'textareafield',
517 name: 'info',
518 fieldLabel: gettext("Comment"),
519 },
520 {
521 xtype: 'textfield',
522 name: 'to',
523 allowBlank: false,
524 value: '__ADMIN__',
525 fieldLabel: gettext('Receiver'),
526 },
527 {
528 xtype: 'textfield',
529 name: 'subject',
530 allowBlank: false,
531 value: 'Notification: __SUBJECT__',
532 fieldLabel: gettext('Subject'),
533 },
534 {
535 xtype: 'textarea',
536 name: 'body',
537 allowBlank: false,
538 grow: true,
539 growMax: 250,
540 value:
541 "Proxmox Notifcation:\n\n" +
542 "Sender: __SENDER__\n" +
543 "Receiver: __RECEIVERS__\n" +
544 "Targets: __TARGETS__\n\n" +
545 "Subject: __SUBJECT__\n\n" +
546 "Matching Rule: __RULE__\n\n" +
547 "__RULE_INFO__\n\n" +
548 "__VIRUS_INFO__\n" +
549 "__SPAM_INFO__\n",
550 fieldLabel: gettext('Body'),
551 },
552 {
553 xtype: 'proxmoxcheckbox',
554 name: 'attach',
555 fieldLabel: gettext("Attach orig. Mail"),
556 },
557 ],
558 },
559 4003: {
560 onlineHelp: 'pmg_mailfilter_action',
561 xtype: 'proxmoxWindowEdit',
562 subdir: 'field',
563 subject: gettext('Header Attribute'),
564 width: 400,
565 items: [
566 {
567 xtype: 'textfield',
568 name: 'name',
569 allowBlank: false,
570 fieldLabel: gettext('Name'),
571 },
572 {
573 xtype: 'textareafield',
574 name: 'info',
575 fieldLabel: gettext("Comment"),
576 },
577 {
578 xtype: 'textfield',
579 name: 'field',
580 allowBlank: false,
581 fieldLabel: gettext('Field'),
582 },
583 {
584 xtype: 'textfield',
585 reference: 'value',
586 name: 'value',
587 allowBlank: false,
588 fieldLabel: gettext('Value'),
589 },
590 ],
591 },
592 4005: {
593 onlineHelp: 'pmg_mailfilter_action',
594 xtype: 'proxmoxWindowEdit',
595 subdir: 'bcc',
596 subject: gettext('BCC'),
597 width: 400,
598 items: [
599 {
600 xtype: 'textfield',
601 name: 'name',
602 allowBlank: false,
603 fieldLabel: gettext('Name'),
604 },
605 {
606 xtype: 'textareafield',
607 name: 'info',
608 fieldLabel: gettext("Comment"),
609 },
610 {
611 xtype: 'textfield',
612 name: 'target',
613 allowBlank: false,
614 fieldLabel: gettext("Target"),
615 },
616 {
617 xtype: 'proxmoxcheckbox',
618 checked: true,
619 name: 'original',
620 boxLabel: gettext("Send Original Mail"),
621 },
622 ],
623
624 },
625 4007: {
626 onlineHelp: 'pmg_mailfilter_action',
627 xtype: 'proxmoxWindowEdit',
628 subdir: 'removeattachments',
629 subject: gettext('Remove Attachments'),
630 width: 500,
631 items: [
632 {
633 xtype: 'textfield',
634 name: 'name',
635 allowBlank: false,
636 fieldLabel: gettext('Name'),
637 },
638 {
639 xtype: 'textareafield',
640 name: 'info',
641 fieldLabel: gettext("Comment"),
642 },
643 {
644 xtype: 'textareafield',
645 name: 'text',
646 grow: true,
647 growMax: 250,
648 fieldLabel: gettext("Text Replacement"),
649 },
650 {
651 xtype: 'proxmoxcheckbox',
652 checked: true,
653 name: 'all',
654 boxLabel: gettext("Remove all Attachments"),
655 },
656 {
657 xtype: 'proxmoxcheckbox',
658 checked: false,
659 name: 'quarantine',
660 boxLabel: gettext("Copy original mail to Attachment Quarantine"),
661 },
662 ],
663 },
664 4009: {
665 onlineHelp: 'pmg_mailfilter_action',
666 xtype: 'proxmoxWindowEdit',
667 subdir: 'disclaimer',
668 subject: gettext('Disclaimer'),
669 width: 400,
670 items: [
671 {
672 xtype: 'textfield',
673 name: 'name',
674 allowBlank: false,
675 fieldLabel: gettext('Name'),
676 },
677 {
678 xtype: 'textareafield',
679 name: 'info',
680 fieldLabel: gettext("Comment"),
681 },
682 {
683 xtype: 'textareafield',
684 name: 'disclaimer',
685 grow: true,
686 growMax: 250,
687 fieldLabel: gettext("Disclaimer"),
688 },
689 {
690 xtype: 'proxmoxKVComboBox',
691 name: 'position',
692 fieldLabel: gettext("Position"),
693 deleteEmpty: false,
694 value: 'end',
695 comboItems: [
696 ['end', gettext('End')],
697 ['start', gettext('Start')],
698 ],
699 },
700 {
701 xtype: 'proxmoxcheckbox',
702 name: 'add-separator',
703 fieldLabel: gettext("Add Separator"),
704 uncheckedValue: '0',
705 value: true,
706 },
707 ],
708 },
709 },
710
711 updateLoginData: function(data) {
712 Proxmox.CSRFPreventionToken = data.CSRFPreventionToken;
713 Proxmox.UserName = data.username;
714 Ext.util.Cookies.set('PMGAuthCookie', data.ticket, null, '/', null, true);
715 },
716
717 quarantineActionExtracted: false,
718
719 extractQuarantineAction: function() {
720 if (PMG.Utils.quarantineActionExtracted) {
721 return null;
722 }
723
724 PMG.Utils.quarantineActionExtracted = true;
725
726 let qs = Ext.Object.fromQueryString(location.search);
727
728 let cselect = qs.cselect;
729 let action = qs.action;
730 let dateString = qs.date;
731
732 if (dateString) {
733 let date = new Date(dateString).getTime()/1000;
734
735 // set from date for QuarantineList
736 PMG.QuarantineList.from = date;
737 }
738
739 delete qs.cselect;
740 delete qs.action;
741 delete qs.ticket;
742 delete qs.date;
743
744 var newsearch = Ext.Object.toQueryString(qs);
745
746 var newurl = location.protocol + "//" + location.host + location.pathname;
747 if (newsearch) { newurl += '?' + newsearch; }
748 newurl += location.hash;
749
750 if (window.history) {
751 window.history.pushState({ path: newurl }, '', newurl);
752 }
753
754 if (action || cselect) {
755 return {
756 action: action,
757 cselect: cselect,
758 };
759 }
760 return null;
761 },
762
763 doQuarantineAction: function(action, id, callback) {
764 Proxmox.Utils.API2Request({
765 url: '/quarantine/content/',
766 params: {
767 action: action,
768 id: id,
769 },
770 method: 'POST',
771 failure: function(response, opts) {
772 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
773 },
774 success: function(response, opts) {
775 let count = id.split(';').length;
776 let fmt = count > 1
777 ? gettext("Action '{0}' for '{1}' items successful")
778 : gettext("Action '{0}' successful")
779 ;
780 let message = Ext.String.format(fmt, action, count);
781 let title = Ext.String.format("{0} successful", Ext.String.capitalize(action));
782
783 Ext.toast({
784 html: message,
785 title: title,
786 minWidth: 200,
787 hideDuration: 250,
788 slideBackDuration: 250,
789 slideBackAnimation: 'easeOut',
790 iconCls: 'fa fa-check',
791 shadow: true,
792 align: 'br',
793 });
794
795 if (Ext.isFunction(callback)) {
796 callback();
797 }
798 },
799 });
800 },
801
802 render_filetype: function(value) {
803 let iconCls = 'fa-file-o';
804 let text = Proxmox.Utils.unknownText;
805
806 if (!value) {
807 return `<i class='fa ${iconCls}'></i> ${text}`;
808 }
809
810 text = value.toString().toLowerCase();
811 const type = text.split('/')[0];
812
813 switch (type) {
814 case 'audio':
815 case 'image':
816 case 'video':
817 case 'text':
818 iconCls = `fa-file-${type}-o`;
819 break;
820 case 'application': {
821 const subtypes = ['excel', 'pdf', 'word', 'powerpoint'];
822 let found = subtypes.find(st => text.includes(st));
823 if (found !== undefined) {
824 iconCls = `fa-file-${found}-o`;
825 }
826 } break;
827 default:
828 break;
829 }
830
831 return `<i class='fa ${iconCls}'></i> ${text}`;
832 },
833
834 render_envelope: function(value, { data }, render_receiver) {
835 let subject = Ext.htmlEncode(value);
836 let from = Ext.htmlEncode(data.from);
837 if (data.sender) {
838 let sender = Ext.htmlEncode(data.sender);
839 from = Ext.String.format(gettext("{0} on behalf of {1}"), sender, from);
840 }
841 if (render_receiver) {
842 let receiver = Ext.htmlEncode(data.receiver);
843 return `<small>${from}<br>To: ${receiver}</small><br>${subject}`;
844 }
845 return `<small>${from}</small><br>${subject}`;
846 },
847
848 render_sender: (value, _meta, rec) => PMG.Utils.render_envelope(value, rec, false),
849 render_sender_receiver: (value, _meta, rec) => PMG.Utils.render_envelope(value, rec, true),
850
851 constructor: function() {
852 var me = this;
853
854 // do whatever you want here
855 Proxmox.Utils.override_task_descriptions({
856 applycustomscores: ['', gettext('Apply custom SpamAssassin scores')],
857 avupdate: ['', gettext('ClamAV update')],
858 backup: ['', gettext('Backup')],
859 clustercreate: ['', gettext('Create Cluster')],
860 clusterjoin: ['', gettext('Join Cluster')],
861 restore: ['', gettext('Restore')],
862 saupdate: ['', gettext('SpamAssassin update')],
863 });
864 },
865 });
866
867 Ext.define('PMG.Async', {
868 singleton: true,
869
870 // Returns a Promise which executes a quarantine action when awaited.
871 // Shows a Toast message box once completed, if batchNumber and batchTotal
872 // are set, they will be included into the title of that toast.
873 doQAction: function(action, ids, batchNumber, batchTotal) {
874 if (!Ext.isArray(ids)) {
875 ids = [ids];
876 }
877 return Proxmox.Async.api2({
878 url: '/quarantine/content/',
879 params: {
880 action: action,
881 id: ids.join(';'),
882 },
883 method: 'POST',
884 }).then(
885 response => {
886 let count = ids.length;
887 let fmt = count > 1
888 ? gettext("Action '{0}' for '{1}' items successful")
889 : gettext("Action '{0}' successful")
890 ;
891 let message = Ext.String.format(fmt, action, count);
892 let titleFmt = batchNumber !== undefined && batchTotal > 1
893 ? gettext("{0} ({1}/{2}) successful")
894 : gettext("{0} successful")
895 ;
896 let title = Ext.String.format(
897 titleFmt,
898 Ext.String.capitalize(action),
899 batchNumber,
900 batchTotal,
901 );
902
903 Ext.toast({
904 html: message,
905 title: title,
906 minWidth: 200,
907 hideDuration: 250,
908 slideBackDuration: 250,
909 slideBackAnimation: 'easeOut',
910 iconCls: 'fa fa-check',
911 shadow: true,
912 align: 'br',
913 });
914 },
915 response => Proxmox.Utils.alertResponseFailure(response),
916 );
917 },
918 });
919
920 // custom Vtypes
921 Ext.apply(Ext.form.field.VTypes, {
922 // matches the pmg-email-address in pmg-api
923 PMGMail: function(v) {
924 return (/^[^\s\\@]+@[^\s/\\@]+$/).test(v);
925 },
926 PMGMailText: gettext('Example') + ": user@example.com",
927 });