]> git.proxmox.com Git - pmg-gui.git/blame - js/LDAPConfig.js
user management: separate add/create and edit/remove buttons
[pmg-gui.git] / js / LDAPConfig.js
CommitLineData
f6b1b3bf
DM
1Ext.define('pmg-ldap-config', {
2 extend: 'Ext.data.Model',
c87d46fb 3 fields: ['profile', 'server1', 'server2', 'comment',
f6b1b3bf
DM
4 'mode', 'binddn', 'bindpw', 'basedn', 'groupbasedn',
5 'filter', 'accountattr', 'mailattr',
c87d46fb
TL
6 { name: 'port', type: 'integer' },
7 { name: 'gcount', type: 'integer' },
8 { name: 'mcount', type: 'integer' },
9 { name: 'ucount', type: 'integer' },
10 { name: 'disable', type: 'boolean' },
f6b1b3bf
DM
11 ],
12 proxy: {
13 type: 'proxmox',
c87d46fb 14 url: "/api2/json/config/ldap",
f6b1b3bf 15 },
c87d46fb 16 idProperty: 'profile',
f6b1b3bf
DM
17});
18
19Ext.define('PMG.LDAPInputPanel', {
20 extend: 'Proxmox.panel.InputPanel',
21 alias: 'widget.pmgLDAPInputPanel',
22
d045660b 23 profileId: undefined,
f6b1b3bf
DM
24
25 onGetValues: function(values) {
26 var me = this;
27
28 values.disable = values.enable ? 0 : 1;
29 delete values.enable;
30
b27d3f1d
DC
31 // do not send empty password
32 if (values.bindpw === '') {
33 delete values.bindpw;
34 }
35
f6b1b3bf
DM
36 return values;
37 },
38
c87d46fb 39 initComponent: function() {
f6b1b3bf
DM
40 var me = this;
41
42 me.column1 = [
43 {
d045660b 44 xtype: me.profileId ? 'displayfield' : 'textfield',
f6b1b3bf 45 fieldLabel: gettext('Profile Name'),
d045660b
DM
46 value: me.profileId || '',
47 name: 'profile',
f6b1b3bf 48 vtype: 'StorageId',
c87d46fb 49 allowBlank: false,
f6b1b3bf
DM
50 },
51 {
52 xtype: 'proxmoxKVComboBox',
53 name: 'mode',
54 comboItems: [
55 ['ldap', PMG.Utils.format_ldap_protocol('ldap')],
3600c3c7 56 ['ldaps', PMG.Utils.format_ldap_protocol('ldaps')],
c87d46fb 57 ['ldap+starttls', PMG.Utils.format_ldap_protocol('ldap+starttls')],
f6b1b3bf
DM
58 ],
59 value: 'ldap',
6bd27800
DC
60 fieldLabel: gettext('Protocol'),
61 listeners: {
62 change: function(cb, value) {
c87d46fb 63 var isldap = value === 'ldap';
6bd27800 64 me.down('field[name=verify]').setVisible(!isldap);
c87d46fb
TL
65 },
66 },
6bd27800
DC
67 },
68 {
69 xtype: 'proxmoxcheckbox',
70 name: 'verify',
71 fieldLabel: gettext('Verify Certificate'),
72 hidden: true,
73 uncheckedValue: 0,
74 value: 1,
c87d46fb 75 checked: 1,
f6b1b3bf
DM
76 },
77 {
78 xtype: 'textfield',
79 fieldLabel: gettext('Server'),
80 allowBlank: false,
479e6fa2 81 vtype: 'DnsOrIp',
c87d46fb 82 name: 'server1',
f6b1b3bf
DM
83 },
84 {
85 xtype: 'proxmoxtextfield',
86 fieldLabel: gettext('Server'),
87 allowBlank: true,
c87d46fb 88 deleteEmpty: !me.isCreate,
479e6fa2 89 vtype: 'DnsOrIp',
c87d46fb 90 name: 'server2',
f6b1b3bf
DM
91 },
92 {
93 xtype: 'proxmoxintegerfield',
94 name: 'port',
95 emptyText: gettext('Default'),
c87d46fb 96 deleteEmpty: !me.isCreate,
f6b1b3bf
DM
97 minValue: 1,
98 maxValue: 65535,
c87d46fb 99 fieldLabel: gettext('Port'),
f6b1b3bf
DM
100 },
101 {
102 xtype: 'textfield',
103 name: 'binddn',
104 allowBlank: true,
c87d46fb 105 fieldLabel: gettext('User name'),
f6b1b3bf
DM
106 },
107 {
108 xtype: 'textfield',
109 inputType: 'password',
110 allowBlank: true,
b27d3f1d 111 emptyText: gettext('Unchanged'),
f6b1b3bf 112 name: 'bindpw',
c87d46fb
TL
113 fieldLabel: gettext('Password'),
114 },
f6b1b3bf
DM
115 ];
116
117 me.column2 = [
118 {
119 xtype: 'proxmoxcheckbox',
120 name: 'enable',
121 checked: true,
122 uncheckedValue: 0,
c87d46fb 123 fieldLabel: gettext('Enable'),
f6b1b3bf
DM
124 },
125 {
126 xtype: 'proxmoxtextfield',
127 allowBlank: true,
c87d46fb 128 deleteEmpty: !me.isCreate,
f6b1b3bf 129 name: 'basedn',
c87d46fb 130 fieldLabel: gettext('Base DN'),
f6b1b3bf
DM
131 },
132 {
133 xtype: 'proxmoxtextfield',
134 allowBlank: true,
c87d46fb 135 deleteEmpty: !me.isCreate,
f6b1b3bf 136 name: 'groupbasedn',
c87d46fb 137 fieldLabel: gettext('Base DN for Groups'),
f6b1b3bf
DM
138 },
139 {
140 xtype: 'proxmoxtextfield',
141 allowBlank: true,
c87d46fb 142 deleteEmpty: !me.isCreate,
f6b1b3bf 143 name: 'mailattr',
c87d46fb 144 fieldLabel: gettext('EMail attribute name(s)'),
f6b1b3bf
DM
145 },
146 {
147 xtype: 'proxmoxtextfield',
148 allowBlank: true,
c87d46fb 149 deleteEmpty: !me.isCreate,
f6b1b3bf 150 name: 'accountattr',
c87d46fb 151 fieldLabel: gettext('Account attribute name'),
f6b1b3bf
DM
152 },
153 {
154 xtype: 'proxmoxtextfield',
155 allowBlank: true,
c87d46fb 156 deleteEmpty: !me.isCreate,
f6b1b3bf 157 name: 'filter',
c87d46fb 158 fieldLabel: gettext('LDAP filter'),
dd26ba9a
DC
159 },
160 {
161 xtype: 'proxmoxtextfield',
162 allowBlank: true,
c87d46fb 163 deleteEmpty: !me.isCreate,
dd26ba9a 164 name: 'groupclass',
c87d46fb
TL
165 fieldLabel: gettext('Group objectclass'),
166 },
f6b1b3bf
DM
167 ];
168
169 me.columnB = [
170 {
171 xtype: 'textfield',
172 fieldLabel: gettext('Comment'),
173 allowBlank: true,
c87d46fb
TL
174 name: 'comment',
175 },
f6b1b3bf
DM
176 ];
177
178 me.callParent();
c87d46fb 179 },
f6b1b3bf
DM
180});
181
182Ext.define('PMG.LDAPEdit', {
183 extend: 'Proxmox.window.Edit',
184 alias: 'widget.pmgLDAPEdit',
573a6e8b 185 onlineHelp: 'pmgconfig_ldap',
f6b1b3bf
DM
186
187 subject: 'LDAP Profile',
188 isAdd: true,
189
c87d46fb 190 initComponent: function() {
f6b1b3bf
DM
191 var me = this;
192
c87d46fb 193 me.isCreate = !me.profileId;
f6b1b3bf 194
18b5b6ad 195 if (me.isCreate) {
f6b1b3bf
DM
196 me.url = '/api2/extjs/config/ldap';
197 me.method = 'POST';
198 } else {
65a2aa68 199 me.url = '/api2/extjs/config/ldap/' + me.profileId + '/config';
f6b1b3bf
DM
200 me.method = 'PUT';
201 }
202
203 var ipanel = Ext.create('PMG.LDAPInputPanel', {
18b5b6ad 204 isCreate: me.isCreate,
c87d46fb 205 profileId: me.profileId,
f6b1b3bf
DM
206 });
207
c87d46fb 208 me.items = [ipanel];
f6b1b3bf
DM
209
210 me.fieldDefaults = {
c87d46fb 211 labelWidth: 150,
f6b1b3bf
DM
212 };
213
214 me.callParent();
215
18b5b6ad 216 if (!me.isCreate) {
f6b1b3bf 217 me.load({
c87d46fb 218 success: function(response, options) {
f6b1b3bf
DM
219 var values = response.result.data;
220
221 values.enable = values.disable ? 0 : 1;
6bd27800 222 values.verify = !!values.verify;
f6b1b3bf 223 ipanel.setValues(values);
c87d46fb 224 },
f6b1b3bf
DM
225 });
226 }
c87d46fb 227 },
f6b1b3bf
DM
228});
229
78ec45eb
DC
230Ext.define('PMG.LDAPUserGrid', {
231 extend: 'Ext.grid.Panel',
232 xtype: 'pmgLDAPUserGrid',
233
234 emptyText: gettext('No data in database'),
235 store: {
236 autoDestroy: true,
c87d46fb 237 fields: ['dn', 'account', 'pmail'],
78ec45eb 238 proxy: { type: 'proxmox' },
c87d46fb 239 sorters: ['dn'],
78ec45eb
DC
240 },
241 columns: [
242 {
243 text: 'DN',
244 dataIndex: 'dn',
c87d46fb 245 flex: 1,
78ec45eb
DC
246 },
247 {
248 text: gettext('Account'),
249 dataIndex: 'account',
c87d46fb 250 flex: 1,
78ec45eb
DC
251 },
252 {
253 text: gettext('Primary E-Mail'),
254 dataIndex: 'pmail',
c87d46fb
TL
255 flex: 1,
256 },
78ec45eb 257 ],
f6b1b3bf 258
78ec45eb 259 initComponent: function() {
f6b1b3bf 260 var me = this;
78ec45eb
DC
261 me.callParent();
262 if (me.url) {
263 me.getStore().getProxy().setUrl(me.url);
264 me.getStore().load();
265 }
c87d46fb 266 },
78ec45eb 267});
f6b1b3bf 268
78ec45eb
DC
269Ext.define('PMG.LDAPConfig', {
270 extend: 'Ext.panel.Panel',
271 xtype: 'pmgLDAPConfig',
272
273 controller: {
274 xclass: 'Ext.app.ViewController',
275
276 openUserList: function(grid, record) {
277 var name = this.getViewModel().get('name');
278 Ext.create('Ext.window.Window', {
279 title: Ext.String.format(gettext("Users of '{0}'"), record.data.dn),
280 modal: true,
281 width: 600,
282 height: 400,
283 layout: 'fit',
284 items: [{
285 xtype: 'pmgLDAPUserGrid',
286 border: false,
c87d46fb
TL
287 url: '/api2/json/config/ldap/' + name + '/groups/' + encodeURIComponent(record.data.gid),
288 }],
78ec45eb
DC
289 }).show();
290 },
291
292 showUsers: function(button) {
293 var me = this;
294 var view = me.lookup('groupgrid');
295 var record = view.getSelection()[0];
296 me.openUserList(view, record);
297 },
298
299 openUserMails: function(grid, record) {
300 var name = this.getViewModel().get('name');
301 Ext.create('Ext.window.Window', {
302 title: Ext.String.format(gettext("E-Mail addresses of '{0}'"), record.data.dn),
303 modal: true,
304 width: 600,
305 height: 400,
306 layout: 'fit',
307 items: [{
308 xtype: 'grid',
309 border: false,
310 store: {
311 autoLoad: true,
312 field: ['email', 'primary'],
313 proxy: {
314 type: 'proxmox',
c87d46fb
TL
315 url: '/api2/json/config/ldap/' + name + '/users/' + encodeURIComponent(record.data.pmail),
316 },
78ec45eb
DC
317 },
318 columns: [
c87d46fb
TL
319 { dataIndex: 'email', text: gettext('E-Mail address'), flex: 1 },
320 ],
321 }],
78ec45eb
DC
322 }).show();
323 },
324
325 showEmails: function(button) {
326 var me = this;
327 var view = me.lookup('usergrid');
328 var record = view.getSelection()[0];
329 me.openUserMails(view, record);
330 },
331
332 reload: function(grid) {
333 var me = this;
334 var selection = grid.getSelection();
335 me.showInfo(grid, selection);
336 },
337
338 showInfo: function(grid, selected) {
339 var me = this;
340 var viewModel = me.getViewModel();
78ec45eb
DC
341 if (selected[0]) {
342 var name = selected[0].data.profile;
343 viewModel.set('selected', true);
344 viewModel.set('name', name);
345
346 // set grid stores and load them
347 var gstore = me.lookup('groupgrid').getStore();
348 var ustore = me.lookup('usergrid').getStore();
349 gstore.getProxy().setUrl('/api2/json/config/ldap/' + name + '/groups');
350 ustore.getProxy().setUrl('/api2/json/config/ldap/' + name + '/users');
351 gstore.load();
352 ustore.load();
353 } else {
354 viewModel.set('selected', false);
f6b1b3bf 355 }
78ec45eb
DC
356 },
357
358 init: function(view) {
359 var me = this;
360 me.lookup('grid').relayEvents(view, ['activate']);
361 var groupgrid = me.lookup('groupgrid');
362 var usergrid = me.lookup('usergrid');
363
364 Proxmox.Utils.monStoreErrors(groupgrid, groupgrid.getStore(), true);
365 Proxmox.Utils.monStoreErrors(usergrid, usergrid.getStore(), true);
366 },
367
368 control: {
369 'grid[reference=grid]': {
370 selectionchange: 'showInfo',
c87d46fb 371 load: 'reload',
78ec45eb
DC
372 },
373 'grid[reference=groupgrid]': {
c87d46fb 374 itemdblclick: 'openUserList',
78ec45eb
DC
375 },
376 'grid[reference=usergrid]': {
c87d46fb
TL
377 itemdblclick: 'openUserMails',
378 },
379 },
78ec45eb 380 },
f6b1b3bf 381
78ec45eb
DC
382 viewModel: {
383 data: {
384 name: '',
c87d46fb
TL
385 selected: false,
386 },
78ec45eb 387 },
f6b1b3bf 388
de0ebd99 389 layout: 'border',
b6850939 390
78ec45eb
DC
391 items: [
392 {
393 region: 'center',
394 reference: 'grid',
395 xtype: 'pmgLDAPConfigGrid',
c87d46fb 396 border: false,
78ec45eb
DC
397 },
398 {
399 xtype: 'tabpanel',
400 reference: 'data',
401 hidden: true,
402 height: '50%',
403 border: false,
404 split: true,
405 region: 'south',
406 bind: {
c87d46fb 407 hidden: '{!selected}',
4ada6d22 408 },
78ec45eb
DC
409 items: [
410 {
411 xtype: 'grid',
412 reference: 'groupgrid',
413 border: false,
414 emptyText: gettext('No data in database'),
415 tbar: [{
416 xtype: 'proxmoxButton',
417 text: gettext('Show Users'),
418 handler: 'showUsers',
c87d46fb 419 disabled: true,
78ec45eb
DC
420 }],
421 store: {
422 fields: ['dn', 'gid'],
423 proxy: { type: 'proxmox' },
c87d46fb 424 sorters: ['dn'],
78ec45eb
DC
425 },
426 bind: {
c87d46fb 427 title: Ext.String.format(gettext("Groups of '{0}'"), '{name}'),
78ec45eb
DC
428 },
429 columns: [
430 {
431 text: 'DN',
432 dataIndex: 'dn',
c87d46fb
TL
433 flex: 1,
434 },
435 ],
78ec45eb
DC
436 },
437 {
438 xtype: 'pmgLDAPUserGrid',
439 reference: 'usergrid',
440 border: false,
441 tbar: [{
442 xtype: 'proxmoxButton',
443 text: gettext('Show E-Mail addresses'),
444 handler: 'showEmails',
c87d46fb 445 disabled: true,
78ec45eb
DC
446 }],
447 bind: {
c87d46fb
TL
448 title: Ext.String.format(gettext("Users of '{0}'"), '{name}'),
449 },
450 },
451 ],
452 },
453 ],
78ec45eb
DC
454
455});
456
457Ext.define('PMG.LDAPConfigGrid', {
458 extend: 'Ext.grid.GridPanel',
459 alias: 'widget.pmgLDAPConfigGrid',
2c18c2d7 460
78ec45eb
DC
461 controller: {
462 xclass: 'Ext.app.ViewController',
463
464 run_editor: function() {
465 var me = this;
466 var view = me.getView();
467 var rec = view.getSelection()[0];
f6b1b3bf
DM
468 if (!rec) {
469 return;
470 }
471
472 var win = Ext.createWidget('pmgLDAPEdit', {
c87d46fb 473 profileId: rec.data.profile,
f6b1b3bf 474 });
78ec45eb 475 win.on('destroy', me.reload, me);
f6b1b3bf 476 win.load();
f6b1b3bf 477 win.show();
78ec45eb 478 },
f6b1b3bf 479
77dab24d 480 newProfile: function() {
78ec45eb
DC
481 var me = this;
482 var win = Ext.createWidget('pmgLDAPEdit', {});
483 win.on('destroy', me.reload, me);
484 win.show();
485 },
486
487
488 reload: function() {
28eb60c0
TL
489 let view = this.getView();
490 view.getStore().load();
491 view.fireEvent('load', view);
78ec45eb
DC
492 },
493
494 sync: function() {
495 var me = this;
496 var view = me.getView();
497 var rec = view.getSelection()[0];
498 Proxmox.Utils.API2Request({
499 url: '/config/ldap/' + rec.data.profile + '/sync',
500 method: 'POST',
501 waitMsgTarget: view,
502 callback: function() {
503 me.reload();
504 },
c87d46fb 505 failure: function(response, opts) {
78ec45eb 506 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
c87d46fb 507 },
78ec45eb
DC
508 });
509 },
f6b1b3bf 510
78ec45eb
DC
511 init: function(view) {
512 var me = this;
513 Proxmox.Utils.monStoreErrors(view, view.getStore(), true);
c87d46fb 514 },
78ec45eb 515 },
b6850939 516
78ec45eb
DC
517 store: {
518 model: 'pmg-ldap-config',
de0ebd99 519 sorters: [{
78ec45eb 520 property: 'profile',
18722987 521 direction: 'ASC',
c87d46fb 522 }],
78ec45eb 523 },
f6b1b3bf 524
78ec45eb 525 tbar: [
eb0a1118
TL
526 {
527 text: gettext('Create'),
528 handler: 'newProfile',
529 },
530 '-',
78ec45eb
DC
531 {
532 xtype: 'proxmoxButton',
533 text: gettext('Edit'),
534 disabled: true,
c87d46fb 535 handler: 'run_editor',
78ec45eb 536 },
78ec45eb
DC
537 {
538 xtype: 'proxmoxStdRemoveButton',
539 baseurl: '/config/ldap',
c87d46fb 540 callback: 'reload',
78ec45eb 541 },
eb0a1118 542 '-',
78ec45eb
DC
543 {
544 xtype: 'proxmoxButton',
545 text: gettext('Synchronize'),
546 enableFn: function(rec) {
547 return !rec.data.disable;
548 },
549 disabled: true,
c87d46fb
TL
550 handler: 'sync',
551 },
78ec45eb
DC
552 ],
553
554 listeners: {
555 itemdblclick: 'run_editor',
c87d46fb 556 activate: 'reload',
78ec45eb
DC
557 },
558
559 columns: [
560 {
561 header: gettext('Profile Name'),
562 sortable: true,
563 width: 120,
c87d46fb 564 dataIndex: 'profile',
78ec45eb
DC
565 },
566 {
567 header: gettext('Protocol'),
568 sortable: true,
569 dataIndex: 'mode',
c87d46fb 570 renderer: PMG.Utils.format_ldap_protocol,
78ec45eb
DC
571 },
572 {
573 header: gettext('Server'),
574 sortable: true,
575 dataIndex: 'server1',
576 renderer: function(value, metaData, rec) {
577 if (rec.data.server2) {
578 return value + '<br>' + rec.data.server2;
579 }
580 return value;
c87d46fb 581 },
78ec45eb
DC
582 },
583 {
584 header: gettext('Enabled'),
585 width: 80,
586 sortable: true,
587 dataIndex: 'disable',
c87d46fb 588 renderer: Proxmox.Utils.format_neg_boolean,
78ec45eb
DC
589 },
590 {
591 header: gettext('Comment'),
592 sortable: false,
593 renderer: Ext.String.htmlEncode,
594 dataIndex: 'comment',
c87d46fb 595 flex: 1,
78ec45eb
DC
596 },
597 {
598 header: gettext('Accounts'),
599 width: 80,
600 sortable: true,
c87d46fb 601 dataIndex: 'ucount',
78ec45eb
DC
602 },
603 {
604 header: gettext('Addresses'),
605 width: 80,
606 sortable: true,
c87d46fb 607 dataIndex: 'mcount',
78ec45eb
DC
608 },
609 {
610 header: gettext('Groups'),
611 width: 80,
612 sortable: true,
c87d46fb
TL
613 dataIndex: 'gcount',
614 },
615 ],
f6b1b3bf 616
f6b1b3bf 617});