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