]> git.proxmox.com Git - pmg-gui.git/blame - js/UserView.js
user management: separate add/create and edit/remove buttons
[pmg-gui.git] / js / UserView.js
CommitLineData
ec1dd829
DM
1Ext.define('pmg-users', {
2 extend: 'Ext.data.Model',
3 fields: [
c87d46fb 4 'userid', 'firstname', 'lastname', 'email', 'comment',
4195a809 5 'role', 'keys', 'realm', 'totp-lock',
ec1dd829 6 { type: 'boolean', name: 'enable' },
c87d46fb 7 { type: 'date', dateFormat: 'timestamp', name: 'expire' },
ec1dd829
DM
8 ],
9 proxy: {
10 type: 'proxmox',
c87d46fb 11 url: "/api2/json/access/users",
ec1dd829 12 },
c87d46fb 13 idProperty: 'userid',
ec1dd829
DM
14});
15
16Ext.define('PMG.UserView', {
17 extend: 'Ext.grid.GridPanel',
18 alias: 'widget.pmgUserView',
19
8f5de6bf
DM
20 store: {
21 autoLoad: true,
22 model: 'pmg-users',
23 sorters: [
24 {
25 property: 'realm',
c87d46fb 26 direction: 'ASC',
8f5de6bf
DM
27 },
28 {
29 property: 'userid',
c87d46fb
TL
30 direction: 'ASC',
31 },
32 ],
8f5de6bf
DM
33 },
34
4468e69c 35 controller: {
ec1dd829 36
4468e69c 37 xclass: 'Ext.app.ViewController',
ec1dd829 38
e93402ee
DM
39 init: function(view) {
40 Proxmox.Utils.monStoreErrors(view, view.store);
41 },
42
4468e69c 43 renderUsername: function(userid) {
fb511cb2 44 return Ext.htmlEncode(userid.match(/^(.+)(@[^@]+)$/)[1]);
4468e69c 45 },
ec1dd829 46
4468e69c
DM
47 renderFullName: function(firstname, metaData, record) {
48 var first = firstname || '';
49 var last = record.data.lastname || '';
fb511cb2 50 return Ext.htmlEncode(first + " " + last);
4468e69c 51 },
ec1dd829 52
4468e69c
DM
53 onAdd: function() {
54 var view = this.getView();
55
56 var win = Ext.create('PMG.UserEdit', {});
131ba4f6 57 win.on('destroy', function() { view.reload(); });
4468e69c
DM
58 win.show();
59 },
60
61 onEdit: function() {
62 var view = this.getView();
ec1dd829 63
4468e69c 64 var rec = view.selModel.getSelection()[0];
ec1dd829
DM
65
66 var win = Ext.create('PMG.UserEdit', {
c87d46fb 67 userid: rec.data.userid,
ec1dd829 68 });
131ba4f6 69 win.on('destroy', function() { view.reload(); });
ec1dd829 70 win.show();
4468e69c
DM
71 },
72
73 onPassword: function(btn, event, rec) {
74 var view = this.getView();
ec1dd829 75
c87d46fb
TL
76 var win = Ext.create('Proxmox.window.PasswordEdit', {
77 userid: rec.data.userid,
4468e69c 78 });
131ba4f6 79 win.on('destroy', function() { view.reload(); });
4468e69c
DM
80 win.show();
81 },
82
83 onAfterRemove: function(btn, res) {
84 var view = this.getView();
85 view.reload();
c87d46fb 86 },
1533ccff
WB
87
88 onUnlockTfa: function(btn, event, rec) {
89 let me = this;
90 let view = me.getView();
91 Ext.Msg.confirm(
92 Ext.String.format(gettext('Unlock TFA authentication for {0}'), rec.data.userid),
93 gettext("Locked 2nd factors can happen if the user's password was leaked. Are you sure you want to unlock the user?"),
94 function(btn_response) {
95 if (btn_response === 'yes') {
96 Proxmox.Utils.API2Request({
97 url: `/access/users/${rec.data.userid}/unlock-tfa`,
98 waitMsgTarget: view,
99 method: 'PUT',
100 failure: function(response, options) {
101 Ext.Msg.alert(gettext('Error'), response.htmlStatus);
102 },
103 success: function(response, options) {
104 view.reload();
105 },
106 });
107 }
108 },
109 );
110 },
4468e69c
DM
111 },
112
113 listeners: {
114 scope: 'controller',
c87d46fb 115 itemdblclick: 'onEdit',
4468e69c
DM
116 },
117
118 tbar: [
119 {
120 text: gettext('Add'),
121 reference: 'addBtn',
c87d46fb 122 handler: 'onAdd',
4468e69c 123 },
eb0a1118 124 '-',
4468e69c
DM
125 {
126 xtype: 'proxmoxButton',
ec1dd829
DM
127 text: gettext('Edit'),
128 disabled: true,
c87d46fb 129 handler: 'onEdit',
4468e69c
DM
130 },
131 {
132 xtype: 'proxmoxStdRemoveButton',
133 baseurl: '/access/users',
134 reference: 'removeBtn',
135 callback: 'onAfterRemove',
c87d46fb 136 waitMsgTarget: true,
4468e69c
DM
137 },
138 {
139 xtype: 'proxmoxButton',
ec1dd829
DM
140 text: gettext('Password'),
141 disabled: true,
c87d46fb
TL
142 handler: 'onPassword',
143 },
1533ccff
WB
144 '-',
145 {
146 xtype: 'proxmoxButton',
147 text: gettext('Unlock TFA'),
148 handler: 'onUnlockTfa',
ff37520d 149 disabled: true,
1533ccff
WB
150 enableFn: ({ data }) =>
151 data['totp-locked'] || (data['tfa-locked-until'] > (new Date().getTime() / 1000)),
152 },
4468e69c 153 ],
ec1dd829 154
4468e69c
DM
155 columns: [
156 {
157 header: gettext('User name'),
158 width: 200,
159 sortable: true,
160 renderer: 'renderUsername',
c87d46fb 161 dataIndex: 'userid',
4468e69c
DM
162 },
163 {
164 header: gettext('Realm'),
165 width: 100,
166 sortable: true,
c87d46fb 167 dataIndex: 'realm',
4468e69c 168 },
7818f0a3
DM
169 {
170 header: gettext('Role'),
171 width: 150,
172 sortable: true,
173 renderer: PMG.Utils.format_user_role,
c87d46fb 174 dataIndex: 'role',
7818f0a3 175 },
4468e69c
DM
176 {
177 header: gettext('Enabled'),
178 width: 80,
179 sortable: true,
180 renderer: Proxmox.Utils.format_boolean,
c87d46fb 181 dataIndex: 'enable',
4468e69c
DM
182 },
183 {
184 header: gettext('Expire'),
185 width: 80,
186 sortable: true,
187 renderer: Proxmox.Utils.format_expire,
c87d46fb 188 dataIndex: 'expire',
4468e69c
DM
189 },
190 {
191 header: gettext('Name'),
192 width: 150,
193 sortable: true,
194 renderer: 'renderFullName',
c87d46fb 195 dataIndex: 'firstname',
4468e69c 196 },
4195a809
WB
197 {
198 header: gettext('TFA Lock'),
199 width: 120,
200 sortable: true,
201 dataIndex: 'totp-locked',
202 renderer: function(v, metaData, record) {
203 let locked_until = record.data['tfa-locked-until'];
204 if (locked_until !== undefined) {
205 let now = new Date().getTime() / 1000;
206 if (locked_until > now) {
207 return gettext('Locked');
208 }
209 }
210
211 if (record.data['totp-locked']) {
212 return gettext('TOTP Locked');
213 }
214
215 return Proxmox.Utils.noText;
216 },
217 },
4468e69c
DM
218 {
219 header: gettext('Comment'),
220 sortable: false,
221 renderer: Ext.String.htmlEncode,
222 dataIndex: 'comment',
c87d46fb
TL
223 flex: 1,
224 },
4468e69c 225 ],
ec1dd829 226
4468e69c
DM
227 reload: function() {
228 var me = this;
ec1dd829 229
4468e69c 230 me.store.load();
c87d46fb 231 },
ec1dd829 232});