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