]> git.argeo.org Git - lgpl/argeo-commons.git/blob - e4/users/GroupEditor.java
Prepare next development cycle
[lgpl/argeo-commons.git] / e4 / users / GroupEditor.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.setProperty;
19 import static org.argeo.naming.LdapAttrs.businessCategory;
20 import static org.argeo.naming.LdapAttrs.description;
21 import static org.argeo.node.NodeInstance.WORKGROUP;
22
23 import java.util.ArrayList;
24 import java.util.Iterator;
25 import java.util.List;
26
27 import javax.annotation.PreDestroy;
28 import javax.inject.Inject;
29 import javax.jcr.Node;
30 import javax.jcr.Repository;
31 import javax.jcr.RepositoryException;
32 import javax.jcr.Session;
33 import javax.naming.InvalidNameException;
34 import javax.naming.ldap.LdapName;
35 import javax.transaction.UserTransaction;
36
37 import org.argeo.cms.CmsException;
38 import org.argeo.cms.e4.users.providers.CommonNameLP;
39 import org.argeo.cms.e4.users.providers.MailLP;
40 import org.argeo.cms.e4.users.providers.RoleIconLP;
41 import org.argeo.cms.e4.users.providers.UserFilter;
42 import org.argeo.cms.ui.eclipse.forms.AbstractFormPart;
43 import org.argeo.cms.ui.eclipse.forms.IManagedForm;
44 import org.argeo.cms.util.CmsUtils;
45 import org.argeo.cms.util.UserAdminUtils;
46 import org.argeo.eclipse.ui.ColumnDefinition;
47 import org.argeo.eclipse.ui.EclipseUiUtils;
48 import org.argeo.eclipse.ui.parts.LdifUsersTable;
49 import org.argeo.jcr.JcrUtils;
50 import org.argeo.naming.LdapAttrs;
51 import org.argeo.node.NodeInstance;
52 import org.argeo.node.NodeUtils;
53 import org.eclipse.e4.ui.workbench.modeling.EPartService;
54 import org.eclipse.jface.action.Action;
55 import org.eclipse.jface.action.ToolBarManager;
56 import org.eclipse.jface.dialogs.MessageDialog;
57 import org.eclipse.jface.resource.ImageDescriptor;
58 import org.eclipse.jface.viewers.ISelection;
59 import org.eclipse.jface.viewers.IStructuredSelection;
60 import org.eclipse.jface.viewers.TableViewer;
61 import org.eclipse.jface.viewers.ViewerDropAdapter;
62 import org.eclipse.swt.SWT;
63 import org.eclipse.swt.dnd.DND;
64 import org.eclipse.swt.dnd.DropTargetEvent;
65 import org.eclipse.swt.dnd.TextTransfer;
66 import org.eclipse.swt.dnd.Transfer;
67 import org.eclipse.swt.dnd.TransferData;
68 import org.eclipse.swt.events.ModifyListener;
69 import org.eclipse.swt.events.SelectionAdapter;
70 import org.eclipse.swt.events.SelectionEvent;
71 import org.eclipse.swt.layout.GridData;
72 import org.eclipse.swt.layout.GridLayout;
73 import org.eclipse.swt.widgets.Composite;
74 import org.eclipse.swt.widgets.Label;
75 import org.eclipse.swt.widgets.Link;
76 import org.eclipse.swt.widgets.Shell;
77 import org.eclipse.swt.widgets.Text;
78 import org.eclipse.swt.widgets.ToolBar;
79 import org.osgi.service.useradmin.Group;
80 import org.osgi.service.useradmin.Role;
81 //import org.eclipse.ui.forms.AbstractFormPart;
82 //import org.eclipse.ui.forms.IManagedForm;
83 //import org.eclipse.ui.forms.SectionPart;
84 //import org.eclipse.ui.forms.editor.FormEditor;
85 //import org.eclipse.ui.forms.editor.FormPage;
86 //import org.eclipse.ui.forms.widgets.FormToolkit;
87 //import org.eclipse.ui.forms.widgets.ScrolledForm;
88 //import org.eclipse.ui.forms.widgets.Section;
89 import org.osgi.service.useradmin.User;
90 import org.osgi.service.useradmin.UserAdmin;
91 import org.osgi.service.useradmin.UserAdminEvent;
92
93 /** Display/edit main properties of a given group */
94 public class GroupEditor extends AbstractRoleEditor {
95 // final static String ID = "GroupEditor.mainPage";
96
97 @Inject
98 private EPartService partService;
99
100 // private final UserEditor editor;
101 @Inject
102 private Repository repository;
103 @Inject
104 private NodeInstance nodeInstance;
105 // private final UserAdminWrapper userAdminWrapper;
106 private Session session;
107
108 // public GroupMainPage(FormEditor editor, UserAdminWrapper userAdminWrapper,
109 // Repository repository,
110 // NodeInstance nodeInstance) {
111 // super(editor, ID, "Main");
112 // try {
113 // session = repository.login();
114 // } catch (RepositoryException e) {
115 // throw new CmsException("Cannot retrieve session of in MainGroupPage
116 // constructor", e);
117 // }
118 // this.editor = (UserEditor) editor;
119 // this.userAdminWrapper = userAdminWrapper;
120 // this.nodeInstance = nodeInstance;
121 // }
122
123 // protected void createFormContent(final IManagedForm mf) {
124 // ScrolledForm form = mf.getForm();
125 // Composite body = form.getBody();
126 // GridLayout mainLayout = new GridLayout();
127 // body.setLayout(mainLayout);
128 // Group group = (Group) editor.getDisplayedUser();
129 // appendOverviewPart(body, group);
130 // appendMembersPart(body, group);
131 // }
132
133 @Override
134 protected void createUi(Composite parent) {
135 try {
136 session = repository.login();
137 } catch (RepositoryException e) {
138 throw new CmsException("Cannot retrieve session", e);
139 }
140 // ScrolledForm form = mf.getForm();
141 // Composite body = form.getBody();
142 // Composite body = new Composite(parent, SWT.NONE);
143 Composite body = parent;
144 GridLayout mainLayout = new GridLayout();
145 body.setLayout(mainLayout);
146 Group group = (Group) getDisplayedUser();
147 appendOverviewPart(body, group);
148 appendMembersPart(body, group);
149 }
150
151 @PreDestroy
152 public void dispose() {
153 JcrUtils.logoutQuietly(session);
154 super.dispose();
155 }
156
157 /** Creates the general section */
158 protected void appendOverviewPart(final Composite parent, final Group group) {
159 Composite body = new Composite(parent, SWT.NONE);
160 // GridLayout layout = new GridLayout(5, false);
161 GridLayout layout = new GridLayout(2, false);
162 body.setLayout(layout);
163 body.setLayoutData(CmsUtils.fillWidth());
164
165 String cn = UserAdminUtils.getProperty(group, LdapAttrs.cn.name());
166 createReadOnlyLT(body, "Name", cn);
167 createReadOnlyLT(body, "DN", group.getName());
168 createReadOnlyLT(body, "Domain", UserAdminUtils.getDomainName(group));
169
170 // Description
171 Label descLbl = new Label(body, SWT.LEAD);
172 descLbl.setFont(EclipseUiUtils.getBoldFont(body));
173 descLbl.setText("Description");
174 descLbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, true, false, 2, 1));
175 final Text descTxt = new Text(body, SWT.LEAD | SWT.MULTI | SWT.WRAP | SWT.BORDER);
176 GridData gd = EclipseUiUtils.fillWidth();
177 gd.heightHint = 50;
178 gd.horizontalSpan = 2;
179 descTxt.setLayoutData(gd);
180
181 // Mark as workgroup
182 Link markAsWorkgroupLk = new Link(body, SWT.NONE);
183 markAsWorkgroupLk.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 2, 1));
184
185 // create form part (controller)
186 final AbstractFormPart part = new AbstractFormPart() {
187
188 private MainInfoListener listener;
189
190 @Override
191 public void initialize(IManagedForm form) {
192 super.initialize(form);
193 listener = new MainInfoListener(parent.getDisplay(), this);
194 userAdminWrapper.addListener(listener);
195 }
196
197 @Override
198 public void dispose() {
199 userAdminWrapper.removeListener(listener);
200 super.dispose();
201 }
202
203 public void commit(boolean onSave) {
204 // group.getProperties().put(LdapAttrs.description.name(), descTxt.getText());
205 setProperty(group, description, descTxt.getText());
206 super.commit(onSave);
207 }
208
209 @Override
210 public void refresh() {
211 // dnTxt.setText(group.getName());
212 // cnTxt.setText(UserAdminUtils.getProperty(group, LdapAttrs.cn.name()));
213 descTxt.setText(UserAdminUtils.getProperty(group, LdapAttrs.description.name()));
214 Node workgroupHome = NodeUtils.getGroupHome(session, cn);
215 if (workgroupHome == null)
216 markAsWorkgroupLk.setText("<a>Mark as workgroup</a>");
217 else
218 markAsWorkgroupLk.setText("Configured as workgroup");
219 parent.layout(true, true);
220 super.refresh();
221 }
222 };
223
224 markAsWorkgroupLk.addSelectionListener(new SelectionAdapter() {
225 private static final long serialVersionUID = -6439340898096365078L;
226
227 @Override
228 public void widgetSelected(SelectionEvent e) {
229
230 boolean confirmed = MessageDialog.openConfirm(parent.getShell(), "Mark as workgroup",
231 "Are you sure you want to mark " + cn + " as being a workgroup? ");
232 if (confirmed) {
233 Node workgroupHome = NodeUtils.getGroupHome(session, cn);
234 if (workgroupHome != null)
235 return; // already marked as workgroup, do nothing
236 else
237 try {
238 // improve transaction management
239 userAdminWrapper.beginTransactionIfNeeded();
240 nodeInstance.createWorkgroup(new LdapName(group.getName()));
241 setProperty(group, businessCategory, WORKGROUP);
242 userAdminWrapper.commitOrNotifyTransactionStateChange();
243 userAdminWrapper
244 .notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, group));
245 part.refresh();
246 } catch (InvalidNameException e1) {
247 throw new CmsException("Cannot create Workgroup for " + group.toString(), e1);
248 }
249
250 }
251 }
252 });
253
254 ModifyListener defaultListener = new FormPartML(part);
255 descTxt.addModifyListener(defaultListener);
256 getManagedForm().addPart(part);
257 }
258
259 /** Filtered table with members. Has drag and drop ability */
260 protected void appendMembersPart(Composite parent, Group group) {
261 // Section section = tk.createSection(parent, Section.TITLE_BAR);
262 // section.setText("Members");
263 // section.setLayoutData(EclipseUiUtils.fillAll());
264
265 Composite body = new Composite(parent, SWT.BORDER);
266 body.setLayout(new GridLayout());
267 // section.setClient(body);
268 body.setLayoutData(EclipseUiUtils.fillAll());
269
270 // Define the displayed columns
271 List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
272 columnDefs.add(new ColumnDefinition(new RoleIconLP(), "", 0, 24));
273 columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Name", 150));
274 columnDefs.add(new ColumnDefinition(new MailLP(), "Mail", 150));
275 // columnDefs.add(new ColumnDefinition(new UserNameLP(), "Distinguished Name",
276 // 240));
277
278 // Create and configure the table
279 LdifUsersTable userViewerCmp = new MyUserTableViewer(body, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL,
280 userAdminWrapper.getUserAdmin());
281
282 userViewerCmp.setColumnDefinitions(columnDefs);
283 userViewerCmp.populate(true, false);
284 userViewerCmp.setLayoutData(EclipseUiUtils.fillAll());
285
286 // Controllers
287 TableViewer userViewer = userViewerCmp.getTableViewer();
288 userViewer.addDoubleClickListener(new UserTableDefaultDClickListener(partService));
289 int operations = DND.DROP_COPY | DND.DROP_MOVE;
290 Transfer[] tt = new Transfer[] { TextTransfer.getInstance() };
291 userViewer.addDropSupport(operations, tt,
292 new GroupDropListener(userAdminWrapper, userViewerCmp, (Group) getDisplayedUser()));
293
294 AbstractFormPart part = new GroupMembersPart(userViewerCmp);
295 getManagedForm().addPart(part);
296
297 // remove button
298 // addRemoveAbility(toolBarManager, userViewerCmp.getTableViewer(), group);
299 Action action = new RemoveMembershipAction(userViewer, group, "Remove selected items from this group",
300 SecurityAdminImages.ICON_REMOVE_DESC);
301
302 ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
303 ToolBar toolBar = toolBarManager.createControl(body);
304 toolBar.setLayoutData(CmsUtils.fillWidth());
305
306 toolBarManager.add(action);
307 toolBarManager.update(true);
308
309 }
310
311 // private LdifUsersTable createMemberPart(Composite parent, Group group) {
312 //
313 // // Define the displayed columns
314 // List<ColumnDefinition> columnDefs = new ArrayList<ColumnDefinition>();
315 // columnDefs.add(new ColumnDefinition(new RoleIconLP(), "", 0, 24));
316 // columnDefs.add(new ColumnDefinition(new CommonNameLP(), "Name", 150));
317 // columnDefs.add(new ColumnDefinition(new MailLP(), "Mail", 150));
318 // // columnDefs.add(new ColumnDefinition(new UserNameLP(), "Distinguished
319 // Name",
320 // // 240));
321 //
322 // // Create and configure the table
323 // LdifUsersTable userViewerCmp = new MyUserTableViewer(parent, SWT.MULTI |
324 // SWT.H_SCROLL | SWT.V_SCROLL,
325 // userAdminWrapper.getUserAdmin());
326 //
327 // userViewerCmp.setColumnDefinitions(columnDefs);
328 // userViewerCmp.populate(true, false);
329 // userViewerCmp.setLayoutData(EclipseUiUtils.fillAll());
330 //
331 // // Controllers
332 // TableViewer userViewer = userViewerCmp.getTableViewer();
333 // userViewer.addDoubleClickListener(new
334 // UserTableDefaultDClickListener(partService));
335 // int operations = DND.DROP_COPY | DND.DROP_MOVE;
336 // Transfer[] tt = new Transfer[] { TextTransfer.getInstance() };
337 // userViewer.addDropSupport(operations, tt,
338 // new GroupDropListener(userAdminWrapper, userViewerCmp, (Group)
339 // getDisplayedUser()));
340 //
341 // // userViewerCmp.refresh();
342 // return userViewerCmp;
343 // }
344
345 // Local viewers
346 private class MyUserTableViewer extends LdifUsersTable {
347 private static final long serialVersionUID = 8467999509931900367L;
348
349 private final UserFilter userFilter;
350
351 public MyUserTableViewer(Composite parent, int style, UserAdmin userAdmin) {
352 super(parent, style, true);
353 userFilter = new UserFilter();
354
355 }
356
357 @Override
358 protected List<User> listFilteredElements(String filter) {
359 // reload user and set it in the editor
360 Group group = (Group) getDisplayedUser();
361 Role[] roles = group.getMembers();
362 List<User> users = new ArrayList<User>();
363 userFilter.setSearchText(filter);
364 // userFilter.setShowSystemRole(true);
365 for (Role role : roles)
366 // if (role.getType() == Role.GROUP)
367 if (userFilter.select(null, null, role))
368 users.add((User) role);
369 return users;
370 }
371 }
372
373 // private void addRemoveAbility(ToolBarManager toolBarManager, TableViewer
374 // userViewer, Group group) {
375 // // Section section = sectionPart.getSection();
376 // // ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);
377 // // ToolBar toolbar = toolBarManager.createControl(parent);
378 // // ToolBar toolbar = toolBarManager.getControl();
379 // // final Cursor handCursor = new Cursor(toolbar.getDisplay(),
380 // SWT.CURSOR_HAND);
381 // // toolbar.setCursor(handCursor);
382 // // toolbar.addDisposeListener(new DisposeListener() {
383 // // private static final long serialVersionUID = 3882131405820522925L;
384 // //
385 // // public void widgetDisposed(DisposeEvent e) {
386 // // if ((handCursor != null) && (handCursor.isDisposed() == false)) {
387 // // handCursor.dispose();
388 // // }
389 // // }
390 // // });
391 //
392 // Action action = new RemoveMembershipAction(userViewer, group, "Remove
393 // selected items from this group",
394 // SecurityAdminImages.ICON_REMOVE_DESC);
395 // toolBarManager.add(action);
396 // toolBarManager.update(true);
397 // // section.setTextClient(toolbar);
398 // }
399
400 private class RemoveMembershipAction extends Action {
401 private static final long serialVersionUID = -1337713097184522588L;
402
403 private final TableViewer userViewer;
404 private final Group group;
405
406 RemoveMembershipAction(TableViewer userViewer, Group group, String name, ImageDescriptor img) {
407 super(name, img);
408 this.userViewer = userViewer;
409 this.group = group;
410 }
411
412 @Override
413 public void run() {
414 ISelection selection = userViewer.getSelection();
415 if (selection.isEmpty())
416 return;
417
418 @SuppressWarnings("unchecked")
419 Iterator<User> it = ((IStructuredSelection) selection).iterator();
420 List<User> users = new ArrayList<User>();
421 while (it.hasNext()) {
422 User currUser = it.next();
423 users.add(currUser);
424 }
425
426 userAdminWrapper.beginTransactionIfNeeded();
427 for (User user : users) {
428 group.removeMember(user);
429 }
430 userAdminWrapper.commitOrNotifyTransactionStateChange();
431 userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, group));
432 }
433 }
434
435 // LOCAL CONTROLLERS
436 private class GroupMembersPart extends AbstractFormPart {
437 private final LdifUsersTable userViewer;
438 // private final Group group;
439
440 private GroupChangeListener listener;
441
442 public GroupMembersPart(LdifUsersTable userViewer) {
443 // super(section);
444 this.userViewer = userViewer;
445 // this.group = group;
446 }
447
448 @Override
449 public void initialize(IManagedForm form) {
450 super.initialize(form);
451 listener = new GroupChangeListener(userViewer.getDisplay(), GroupMembersPart.this);
452 userAdminWrapper.addListener(listener);
453 }
454
455 @Override
456 public void dispose() {
457 userAdminWrapper.removeListener(listener);
458 super.dispose();
459 }
460
461 @Override
462 public void refresh() {
463 userViewer.refresh();
464 super.refresh();
465 }
466 }
467
468 /**
469 * Defines this table as being a potential target to add group membership
470 * (roles) to this group
471 */
472 private class GroupDropListener extends ViewerDropAdapter {
473 private static final long serialVersionUID = 2893468717831451621L;
474
475 private final UserAdminWrapper userAdminWrapper;
476 // private final LdifUsersTable myUserViewerCmp;
477 private final Group myGroup;
478
479 public GroupDropListener(UserAdminWrapper userAdminWrapper, LdifUsersTable userTableViewerCmp, Group group) {
480 super(userTableViewerCmp.getTableViewer());
481 this.userAdminWrapper = userAdminWrapper;
482 this.myGroup = group;
483 // this.myUserViewerCmp = userTableViewerCmp;
484 }
485
486 @Override
487 public boolean validateDrop(Object target, int operation, TransferData transferType) {
488 // Target is always OK in a list only view
489 // TODO check if not a string
490 boolean validDrop = true;
491 return validDrop;
492 }
493
494 @Override
495 public void drop(DropTargetEvent event) {
496 // TODO Is there an opportunity to perform the check before?
497 String newUserName = (String) event.data;
498 UserAdmin myUserAdmin = userAdminWrapper.getUserAdmin();
499 Role role = myUserAdmin.getRole(newUserName);
500 if (role.getType() == Role.GROUP) {
501 Group newGroup = (Group) role;
502 Shell shell = getViewer().getControl().getShell();
503 // Sanity checks
504 if (myGroup == newGroup) { // Equality
505 MessageDialog.openError(shell, "Forbidden addition ", "A group cannot be a member of itself.");
506 return;
507 }
508
509 // Cycle
510 String myName = myGroup.getName();
511 List<User> myMemberships = getFlatGroups(myGroup);
512 if (myMemberships.contains(newGroup)) {
513 MessageDialog.openError(shell, "Forbidden addition: cycle",
514 "Cannot add " + newUserName + " to group " + myName + ". This would create a cycle");
515 return;
516 }
517
518 // Already member
519 List<User> newGroupMemberships = getFlatGroups(newGroup);
520 if (newGroupMemberships.contains(myGroup)) {
521 MessageDialog.openError(shell, "Forbidden addition",
522 "Cannot add " + newUserName + " to group " + myName + ", this membership already exists");
523 return;
524 }
525 userAdminWrapper.beginTransactionIfNeeded();
526 myGroup.addMember(newGroup);
527 userAdminWrapper.commitOrNotifyTransactionStateChange();
528 userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, myGroup));
529 } else if (role.getType() == Role.USER) {
530 // TODO check if the group is already member of this group
531 UserTransaction transaction = userAdminWrapper.beginTransactionIfNeeded();
532 User user = (User) role;
533 myGroup.addMember(user);
534 if (UserAdminWrapper.COMMIT_ON_SAVE)
535 try {
536 transaction.commit();
537 } catch (Exception e) {
538 throw new CmsException("Cannot commit transaction " + "after user group membership update", e);
539 }
540 userAdminWrapper.notifyListeners(new UserAdminEvent(null, UserAdminEvent.ROLE_CHANGED, myGroup));
541 }
542 super.drop(event);
543 }
544
545 @Override
546 public boolean performDrop(Object data) {
547 // myUserViewerCmp.refresh();
548 return true;
549 }
550 }
551
552 // LOCAL HELPERS
553 // private Composite addSection(FormToolkit tk, Composite parent) {
554 // Section section = tk.createSection(parent, SWT.NO_FOCUS);
555 // section.setLayoutData(EclipseUiUtils.fillWidth());
556 // Composite body = tk.createComposite(section, SWT.WRAP);
557 // body.setLayoutData(EclipseUiUtils.fillAll());
558 // section.setClient(body);
559 // return body;
560 // }
561
562 /** Creates label and text. */
563 // private Text createLT(Composite parent, String label, String value) {
564 // FormToolkit toolkit = getManagedForm().getToolkit();
565 // Label lbl = toolkit.createLabel(parent, label);
566 // lbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false));
567 // lbl.setFont(EclipseUiUtils.getBoldFont(parent));
568 // Text text = toolkit.createText(parent, value, SWT.BORDER);
569 // text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
570 // CmsUtils.style(text, CmsWorkbenchStyles.WORKBENCH_FORM_TEXT);
571 // return text;
572 // }
573 //
574 // Text createReadOnlyLT(Composite parent, String label, String value) {
575 // FormToolkit toolkit = getManagedForm().getToolkit();
576 // Label lbl = toolkit.createLabel(parent, label);
577 // lbl.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false));
578 // lbl.setFont(EclipseUiUtils.getBoldFont(parent));
579 // Text text = toolkit.createText(parent, value, SWT.NONE);
580 // text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
581 // text.setEditable(false);
582 // CmsUtils.style(text, CmsWorkbenchStyles.WORKBENCH_FORM_TEXT);
583 // return text;
584 // }
585
586 }