]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms.e4/src/org/argeo/cms/e4/users/UserEditor.java
Introduce E4 privileged job
[lgpl/argeo-commons.git] / org.argeo.cms.e4 / src / org / argeo / cms / e4 / users / UserEditor.java
1 /*
2 * Copyright (C) 2007-2012 Argeo GmbH
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.argeo.cms.e4.users;
17
18 import static org.argeo.cms.util.UserAdminUtils.getProperty;
19 import static org.argeo.naming.LdapAttrs.cn;
20 import static org.argeo.naming.LdapAttrs.givenName;
21 import static org.argeo.naming.LdapAttrs.mail;
22 import static org.argeo.naming.LdapAttrs.sn;
23 import static org.argeo.naming.LdapAttrs.uid;
24
25 import java.util.ArrayList;
26 import java.util.Iterator;
27 import java.util.List;
28
29 import javax.inject.Inject;
30
31 import org.argeo.cms.ArgeoNames;
32 import org.argeo.cms.auth.CurrentUser;
33 import org.argeo.cms.e4.users.providers.CommonNameLP;
34 import org.argeo.cms.e4.users.providers.DomainNameLP;
35 import org.argeo.cms.e4.users.providers.RoleIconLP;
36 import org.argeo.cms.e4.users.providers.UserFilter;
37 import org.argeo.cms.ui.eclipse.forms.AbstractFormPart;
38 //import org.argeo.cms.ui.eclipse.forms.FormToolkit;
39 import org.argeo.cms.ui.eclipse.forms.IManagedForm;
40 import org.argeo.cms.util.CmsUtils;
41 import org.argeo.cms.util.UserAdminUtils;
42 import org.argeo.eclipse.ui.ColumnDefinition;
43 import org.argeo.eclipse.ui.EclipseUiUtils;
44 import org.argeo.eclipse.ui.parts.LdifUsersTable;
45 import org.argeo.naming.LdapAttrs;
46 import org.argeo.node.NodeConstants;
47 import org.eclipse.e4.ui.workbench.modeling.EPartService;
48 import org.eclipse.jface.action.Action;
49 import org.eclipse.jface.action.ToolBarManager;
50 import org.eclipse.jface.dialogs.MessageDialog;
51 import org.eclipse.jface.dialogs.TrayDialog;
52 import org.eclipse.jface.resource.ImageDescriptor;
53 import org.eclipse.jface.viewers.ISelection;
54 import org.eclipse.jface.viewers.IStructuredSelection;
55 import org.eclipse.jface.viewers.TableViewer;
56 import org.eclipse.jface.viewers.Viewer;
57 import org.eclipse.jface.viewers.ViewerDropAdapter;
58 import org.eclipse.swt.SWT;
59 import org.eclipse.swt.dnd.DND;
60 import org.eclipse.swt.dnd.DropTargetEvent;
61 import org.eclipse.swt.dnd.TextTransfer;
62 import org.eclipse.swt.dnd.Transfer;
63 import org.eclipse.swt.dnd.TransferData;
64 import org.eclipse.swt.events.ModifyEvent;
65 import org.eclipse.swt.events.ModifyListener;
66 import org.eclipse.swt.events.SelectionAdapter;
67 import org.eclipse.swt.events.SelectionEvent;
68 import org.eclipse.swt.layout.GridData;
69 import org.eclipse.swt.layout.GridLayout;
70 import org.eclipse.swt.widgets.Button;
71 import org.eclipse.swt.widgets.Composite;
72 import org.eclipse.swt.widgets.Control;
73 import org.eclipse.swt.widgets.Display;
74 import org.eclipse.swt.widgets.Link;
75 import org.eclipse.swt.widgets.Shell;
76 import org.eclipse.swt.widgets.Text;
77 import org.eclipse.swt.widgets.ToolBar;
78 import org.osgi.service.useradmin.Group;
79 import org.osgi.service.useradmin.Role;
80 import org.osgi.service.useradmin.User;
81 import org.osgi.service.useradmin.UserAdmin;
82 import org.osgi.service.useradmin.UserAdminEvent;
83
84 /** Display/edit the properties of a given user */
85 public class UserEditor extends AbstractRoleEditor implements ArgeoNames {
86 // final static String ID = "UserEditor.mainPage";
87
88 @Inject
89 private EPartService partService;
90
91 // private final UserEditor editor;
92 // private UserAdminWrapper userAdminWrapper;
93
94 // Local configuration
95 // private final int PRE_TITLE_INDENT = 10;
96
97 // public UserMainPage(FormEditor editor, UserAdminWrapper userAdminWrapper) {
98 // super(editor, ID, "Main");
99 // this.editor = (UserEditor) editor;
100 // this.userAdminWrapper = userAdminWrapper;
101 // }
102
103 // protected void createFormContent(final IManagedForm mf) {
104 // ScrolledForm form = mf.getForm();
105 // Composite body = form.getBody();
106 // GridLayout mainLayout = new GridLayout();
107 // // mainLayout.marginRight = 10;
108 // body.setLayout(mainLayout);
109 // User user = editor.getDisplayedUser();
110 // appendOverviewPart(body, user);
111 // // Remove to ability to force the password for his own user. The user
112 // // must then use the change pwd feature
113 // appendMemberOfPart(body, user);
114 // }
115
116 @Override
117 protected void createUi(Composite body) {
118 // Composite body = new Composite(parent, SWT.BORDER);
119 GridLayout mainLayout = new GridLayout();
120 // mainLayout.marginRight = 10;
121 body.setLayout(mainLayout);
122 // body.getParent().setLayout(new GridLayout());
123 // body.setLayoutData(CmsUtils.fillAll());
124 User user = getDisplayedUser();
125 appendOverviewPart(body, user);
126 // Remove to ability to force the password for his own user. The user
127 // must then use the change pwd feature
128 appendMemberOfPart(body, user);
129 }
130
131 /** Creates the general section */
132 private void appendOverviewPart(final Composite parent, final User user) {
133 // FormToolkit tk = getManagedForm().getToolkit();
134
135 // Section section = tk.createSection(parent, SWT.NO_FOCUS);
136 // GridData gd = EclipseUiUtils.fillWidth();
137 // // gd.verticalAlignment = PRE_TITLE_INDENT;
138 // section.setLayoutData(gd);
139 Composite body = new Composite(parent, SWT.NONE);
140 body.setLayoutData(EclipseUiUtils.fillWidth());
141 // section.setClient(body);
142 // body.setLayout(new GridLayout(6, false));
143 body.setLayout(new GridLayout(2, false));
144
145 Text commonName = createReadOnlyLT(body, "Name", getProperty(user, cn));
146 Text distinguishedName = createReadOnlyLT(body, "Login", getProperty(user, uid));
147 Text firstName = createLT(body, "First name", getProperty(user, givenName));
148 Text lastName = createLT(body, "Last name", getProperty(user, sn));
149 Text email = createLT(body, "Email", getProperty(user, mail));
150
151 Link resetPwdLk = new Link(body, SWT.NONE);
152 if (!UserAdminUtils.isCurrentUser(user)) {
153 resetPwdLk.setText("<a>Reset password</a>");
154 }
155 resetPwdLk.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
156
157 // create form part (controller)
158 AbstractFormPart part = new AbstractFormPart() {
159 private MainInfoListener listener;
160
161 @Override
162 public void initialize(IManagedForm form) {
163 super.initialize(form);
164 listener = new MainInfoListener(parent.getDisplay(), this);
165 userAdminWrapper.addListener(listener);
166 }
167
168 @Override
169 public void dispose() {
170 userAdminWrapper.removeListener(listener);
171 super.dispose();
172 }
173
174 @SuppressWarnings("unchecked")
175 public void commit(boolean onSave) {
176 // TODO Sanity checks (mail validity...)
177 user.getProperties().put(LdapAttrs.givenName.name(), firstName.getText());
178 user.getProperties().put(LdapAttrs.sn.name(), lastName.getText());
179 user.getProperties().put(LdapAttrs.cn.name(), commonName.getText());
180 user.getProperties().put(LdapAttrs.mail.name(), email.getText());
181 super.commit(onSave);
182 }
183
184 @Override
185 public void refresh() {
186 distinguishedName.setText(UserAdminUtils.getProperty(user, LdapAttrs.uid.name()));
187 commonName.setText(UserAdminUtils.getProperty(user, LdapAttrs.cn.name()));
188 firstName.setText(UserAdminUtils.getProperty(user, LdapAttrs.givenName.name()));
189 lastName.setText(UserAdminUtils.getProperty(user, LdapAttrs.sn.name()));
190 email.setText(UserAdminUtils.getProperty(user, LdapAttrs.mail.name()));
191 refreshFormTitle(user);
192 super.refresh();
193 }
194 };
195
196 // Improve this: automatically generate CN when first or last name
197 // changes
198 ModifyListener cnML = new ModifyListener() {
199 private static final long serialVersionUID = 4298649222869835486L;
200
201 @Override
202 public void modifyText(ModifyEvent event) {
203 String first = firstName.getText();
204 String last = lastName.getText();
205 String cn = first.trim() + " " + last.trim() + " ";
206 cn = cn.trim();
207 commonName.setText(cn);
208 // getManagedForm().getForm().setText(cn);
209 updateEditorTitle(cn);
210 }
211 };
212 firstName.addModifyListener(cnML);
213 lastName.addModifyListener(cnML);
214
215 ModifyListener defaultListener = new FormPartML(part);
216 firstName.addModifyListener(defaultListener);
217 lastName.addModifyListener(defaultListener);
218 email.addModifyListener(defaultListener);
219
220 if (!UserAdminUtils.isCurrentUser(user))
221 resetPwdLk.addSelectionListener(new SelectionAdapter() {
222 private static final long serialVersionUID = 5881800534589073787L;
223
224 @Override
225 public void widgetSelected(SelectionEvent e) {
226 new ChangePasswordDialog(user, "Reset password").open();
227 }
228 });
229
230 getManagedForm().addPart(part);
231 }
232
233 private class ChangePasswordDialog extends TrayDialog {
234 private static final long serialVersionUID = 2843538207460082349L;
235
236 private User user;
237 private Text password1;
238 private Text password2;
239 private String title;
240 // private FormToolkit tk;
241
242 public ChangePasswordDialog(User user, String title) {
243 super(Display.getDefault().getActiveShell());
244 // this.tk = tk;
245 this.user = user;
246 this.title = title;
247 }
248
249 protected Control createDialogArea(Composite parent) {
250 Composite dialogarea = (Composite) super.createDialogArea(parent);
251 dialogarea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
252 Composite body = new Composite(dialogarea, SWT.NO_FOCUS);
253 body.setLayoutData(EclipseUiUtils.fillAll());
254 GridLayout layout = new GridLayout(2, false);
255 body.setLayout(layout);
256
257 password1 = createLP(body, "New password", "");
258 password2 = createLP(body, "Repeat password", "");
259 parent.pack();
260 return body;
261 }
262
263 @SuppressWarnings("unchecked")
264 @Override
265 protected void okPressed() {
266 String msg = null;
267
268 if (password1.getText().equals(""))
269 msg = "Password cannot be empty";
270 else if (password1.getText().equals(password2.getText())) {
271 char[] newPassword = password1.getText().toCharArray();
272 // userAdminWrapper.beginTransactionIfNeeded();
273 userAdminWrapper.beginTransactionIfNeeded();
274 user.getCredentials().put(null, newPassword);
275 userAdminWrapper.commitOrNotifyTransactionStateChange();
276 super.okPressed();
277 } else {
278 msg = "Passwords are not equals";
279 }
280
281 if (EclipseUiUtils.notEmpty(msg))
282 MessageDialog.openError(getParentShell(), "Cannot reset pasword", msg);
283 }
284
285 protected void configureShell(Shell shell) {
286 super.configureShell(shell);
287 shell.setText(title);
288 }
289 }
290
291 private LdifUsersTable appendMemberOfPart(final Composite parent, User user) {
292 // Section section = addSection(tk, parent, "Roles");
293 // Composite body = (Composite) section.getClient();
294 // Composite body= parent;
295 Composite body = new Composite(parent, SWT.BORDER);
296 body.setLayout(new GridLayout());
297 body.setLayoutData(CmsUtils.fillAll());
298
299 // boolean isAdmin = CurrentUser.isInRole(NodeConstants.ROLE_ADMIN);
300
301 // Displayed columns
302 List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
303 columnDefs.add(new ColumnDefinition(new RoleIconLP(), "", 0, 24));
304 columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Name", 150));
305 columnDefs.add(new ColumnDefinition(new DomainNameLP(), "Domain", 100));
306 // Only show technical DN to administrators
307 // if (isAdmin)
308 // columnDefs.add(new ColumnDefinition(new UserNameLP(), "Distinguished Name",
309 // 300));
310
311 // Create and configure the table
312 final LdifUsersTable userViewerCmp = new MyUserTableViewer(body, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL, user);
313
314 userViewerCmp.setColumnDefinitions(columnDefs);
315 // if (isAdmin)
316 // userViewerCmp.populateWithStaticFilters(false, false);
317 // else
318 userViewerCmp.populate(true, false);
319 GridData gd = EclipseUiUtils.fillAll();
320 gd.heightHint = 500;
321 userViewerCmp.setLayoutData(gd);
322
323 // Controllers
324 TableViewer userViewer = userViewerCmp.getTableViewer();
325 userViewer.addDoubleClickListener(new UserTableDefaultDClickListener(partService));
326 int operations = DND.DROP_COPY | DND.DROP_MOVE;
327 Transfer[] tt = new Transfer[] { TextTransfer.getInstance() };
328 GroupDropListener dropL = new GroupDropListener(userAdminWrapper, userViewer, user);
329 userViewer.addDropSupport(operations, tt, dropL);
330
331 AbstractFormPart part = new AbstractFormPart() {
332
333 private GroupChangeListener listener;
334
335 @Override
336 public void initialize(IManagedForm form) {
337 super.initialize(form);
338 listener = new GroupChangeListener(parent.getDisplay(), this);
339 userAdminWrapper.addListener(listener);
340 }
341
342 public void commit(boolean onSave) {
343 super.commit(onSave);
344 }
345
346 @Override
347 public void dispose() {
348 userAdminWrapper.removeListener(listener);
349 super.dispose();
350 }
351
352 @Override
353 public void refresh() {
354 userViewerCmp.refresh();
355 super.refresh();
356 }
357 };
358 getManagedForm().addPart(part);
359 // addRemoveAbitily(body, userViewer, user);
360 // userViewerCmp.refresh();
361 String tooltip = "Remove " + UserAdminUtils.getUserLocalId(user.getName()) + " from the below selected groups";
362 Action action = new RemoveMembershipAction(userViewer, user, tooltip, SecurityAdminImages.ICON_REMOVE_DESC);
363 ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
364 ToolBar toolBar = toolBarManager.createControl(body);
365 toolBar.setLayoutData(CmsUtils.fillWidth());
366 toolBarManager.add(action);
367 toolBarManager.update(true);
368 return userViewerCmp;
369 }
370
371 private class MyUserTableViewer extends LdifUsersTable {
372 private static final long serialVersionUID = 2653790051461237329L;
373
374 private Button showSystemRoleBtn;
375
376 private final User user;
377 private final UserFilter userFilter;
378
379 public MyUserTableViewer(Composite parent, int style, User user) {
380 super(parent, style, true);
381 this.user = user;
382 userFilter = new UserFilter();
383 }
384
385 protected void populateStaticFilters(Composite staticFilterCmp) {
386 staticFilterCmp.setLayout(new GridLayout());
387 showSystemRoleBtn = new Button(staticFilterCmp, SWT.CHECK);
388 showSystemRoleBtn.setText("Show system roles");
389 boolean showSysRole = CurrentUser.isInRole(NodeConstants.ROLE_ADMIN);
390 showSystemRoleBtn.setSelection(showSysRole);
391 userFilter.setShowSystemRole(showSysRole);
392 showSystemRoleBtn.addSelectionListener(new SelectionAdapter() {
393 private static final long serialVersionUID = -7033424592697691676L;
394
395 @Override
396 public void widgetSelected(SelectionEvent e) {
397 userFilter.setShowSystemRole(showSystemRoleBtn.getSelection());
398 refresh();
399 }
400 });
401 }
402
403 @Override
404 protected List<User> listFilteredElements(String filter) {
405 List<User> users = (List<User>) getFlatGroups(null);
406 List<User> filteredUsers = new ArrayList<User>();
407 if (users.contains(user))
408 users.remove(user);
409 userFilter.setSearchText(filter);
410 for (User user : users)
411 if (userFilter.select(null, null, user))
412 filteredUsers.add(user);
413 return filteredUsers;
414 }
415 }
416
417 // private void addRemoveAbility(Composite parent, TableViewer userViewer, User
418 // user) {
419 // // Section section = sectionPart.getSection();
420 // ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
421 // ToolBar toolbar = toolBarManager.createControl(parent);
422 // final Cursor handCursor = new Cursor(Display.getCurrent(), SWT.CURSOR_HAND);
423 // toolbar.setCursor(handCursor);
424 // toolbar.addDisposeListener(new DisposeListener() {
425 // private static final long serialVersionUID = 3882131405820522925L;
426 //
427 // public void widgetDisposed(DisposeEvent e) {
428 // if ((handCursor != null) && (handCursor.isDisposed() == false)) {
429 // handCursor.dispose();
430 // }
431 // }
432 // });
433 //
434 // String tooltip = "Remove " + UserAdminUtils.getUserLocalId(user.getName()) +
435 // " from the below selected groups";
436 // Action action = new RemoveMembershipAction(userViewer, user, tooltip,
437 // SecurityAdminImages.ICON_REMOVE_DESC);
438 // toolBarManager.add(action);
439 // toolBarManager.update(true);
440 // // section.setTextClient(toolbar);
441 // }
442
443 private class RemoveMembershipAction extends Action {
444 private static final long serialVersionUID = -1337713097184522588L;
445
446 private final TableViewer userViewer;
447 private final User user;
448
449 RemoveMembershipAction(TableViewer userViewer, User user, String name, ImageDescriptor img) {
450 super(name, img);
451 this.userViewer = userViewer;
452 this.user = user;
453 }
454
455 @Override
456 public void run() {
457 ISelection selection = userViewer.getSelection();
458 if (selection.isEmpty())
459 return;
460
461 @SuppressWarnings("unchecked")
462 Iterator<Group> it = ((IStructuredSelection) selection).iterator();
463 List<Group> groups = new ArrayList<Group>();
464 while (it.hasNext()) {
465 Group currGroup = it.next();
466 groups.add(currGroup);
467 }
468
469 userAdminWrapper.beginTransactionIfNeeded();
470 for (Group group : groups) {
471 group.removeMember(user);
472 }
473 userAdminWrapper.commitOrNotifyTransactionStateChange();
474 for (Group group : groups) {
475 userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, group));
476 }
477 }
478 }
479
480 /**
481 * Defines the table as being a potential target to add group memberships
482 * (roles) to this user
483 */
484 private class GroupDropListener extends ViewerDropAdapter {
485 private static final long serialVersionUID = 2893468717831451621L;
486
487 private final UserAdminWrapper myUserAdminWrapper;
488 private final User myUser;
489
490 public GroupDropListener(UserAdminWrapper userAdminWrapper, Viewer userViewer, User user) {
491 super(userViewer);
492 this.myUserAdminWrapper = userAdminWrapper;
493 this.myUser = user;
494 }
495
496 @Override
497 public boolean validateDrop(Object target, int operation, TransferData transferType) {
498 // Target is always OK in a list only view
499 // TODO check if not a string
500 boolean validDrop = true;
501 return validDrop;
502 }
503
504 @Override
505 public void drop(DropTargetEvent event) {
506 String name = (String) event.data;
507 UserAdmin myUserAdmin = myUserAdminWrapper.getUserAdmin();
508 Role role = myUserAdmin.getRole(name);
509 // TODO this check should be done before.
510 if (role.getType() == Role.GROUP) {
511 // TODO check if the user is already member of this group
512
513 myUserAdminWrapper.beginTransactionIfNeeded();
514 Group group = (Group) role;
515 group.addMember(myUser);
516 userAdminWrapper.commitOrNotifyTransactionStateChange();
517 myUserAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, group));
518 }
519 super.drop(event);
520 }
521
522 @Override
523 public boolean performDrop(Object data) {
524 // userTableViewerCmp.refresh();
525 return true;
526 }
527 }
528
529 // LOCAL HELPERS
530 private void refreshFormTitle(User group) {
531 // getManagedForm().getForm().setText(UserAdminUtils.getProperty(group,
532 // LdapAttrs.cn.name()));
533 }
534
535 /** Appends a section with a title */
536 // private Section addSection(FormToolkit tk, Composite parent, String title) {
537 // Section section = tk.createSection(parent, Section.TITLE_BAR);
538 // GridData gd = EclipseUiUtils.fillWidth();
539 // gd.verticalAlignment = PRE_TITLE_INDENT;
540 // section.setLayoutData(gd);
541 // section.setText(title);
542 // // section.getMenu().setVisible(true);
543 //
544 // Composite body = tk.createComposite(section, SWT.WRAP);
545 // body.setLayoutData(EclipseUiUtils.fillAll());
546 // section.setClient(body);
547 //
548 // return section;
549 // }
550
551 }