--- /dev/null
+package org.argeo.cms.users;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.CmsEditable;
+import org.argeo.cms.CmsUiProvider;
+import org.argeo.cms.CmsUtils;
+import org.argeo.cms.viewers.JcrVersionCmsEditable;
+import org.argeo.cms.widgets.ScrolledPage;
+import org.argeo.security.UserAdminService;
+import org.argeo.security.jcr.JcrSecurityModel;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+
+/** Enable management of a given user */
+public class UserPage implements CmsUiProvider {
+
+ // Enable user CRUD // INJECTED
+ private UserAdminService userAdminService;
+ private JcrSecurityModel jcrSecurityModel;
+
+ // public UserPage(UserAdminService userAdminService,
+ // JcrSecurityModel jcrSecurityModel) {
+ // this.userAdminService = userAdminService;
+ // this.jcrSecurityModel = jcrSecurityModel;
+ // }
+
+ @Override
+ public Control createUi(Composite parent, Node context)
+ throws RepositoryException {
+ CmsEditable cmsEditable = new JcrVersionCmsEditable(context);
+ Composite page = createPage(parent);
+ UserViewer userViewer = new UserViewer(page, SWT.NONE, context,
+ cmsEditable);
+
+ Control control = userViewer.getControl();
+ Composite par = control.getParent();
+
+ new Label(par, SWT.NONE).setText("Work in progress terminate.");
+
+ UserRolesPart rolesPart = new UserRolesPart(par, SWT.NO_FOCUS, context,
+ true);
+ rolesPart.setUserAdminService(userAdminService);
+ rolesPart.createControl(rolesPart, UserStyles.USER_FORM_TEXT);
+ rolesPart.refresh();
+
+ return page;
+ }
+
+ protected Composite createPage(Composite parent) {
+ parent.setLayout(CmsUtils.noSpaceGridLayout());
+ ScrolledPage scrolled = new ScrolledPage(parent, SWT.NONE);
+ scrolled.setLayoutData(CmsUtils.fillAll());
+ scrolled.setLayout(CmsUtils.noSpaceGridLayout());
+ // TODO manage style
+ // CmsUtils.style(scrolled, "maintenance_user_form");
+
+ Composite page = new Composite(scrolled, SWT.NONE);
+ page.setLayout(CmsUtils.noSpaceGridLayout());
+ page.setBackgroundMode(SWT.INHERIT_NONE);
+ page.setLayoutData(CmsUtils.fillAll());
+ return page;
+ }
+
+ public void setUserAdminService(UserAdminService userAdminService) {
+ this.userAdminService = userAdminService;
+ }
+
+ public void setJcrSecurityModel(JcrSecurityModel jcrSecurityModel) {
+ this.jcrSecurityModel = jcrSecurityModel;
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.users;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Item;
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+
+import org.argeo.ArgeoException;
+import org.argeo.cms.CmsUtils;
+import org.argeo.cms.viewers.EditablePart;
+import org.argeo.cms.viewers.NodePart;
+import org.argeo.cms.widgets.StyledControl;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.jcr.ArgeoNames;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+/** Display a single user main info once it has been created. */
+public class UserPart extends StyledControl implements EditablePart, NodePart,
+ FocusListener {
+ private static final long serialVersionUID = -2883661960366940505L;
+ // private final static Log log = LogFactory.getLog(UserPart.class);
+
+ // A static list of supported properties.
+ private List<Text> texts;
+ private final static String KEY_PROP_NAME = "jcr:propertyName";
+
+ // TODO implement to provide user creation ability for anonymous user?
+ // public UserPart(Composite parent, int swtStyle) {
+ // super(parent, swtStyle);
+ // }
+
+ public UserPart(Composite parent, int style, Item item)
+ throws RepositoryException {
+ this(parent, style, item, true);
+ }
+
+ public UserPart(Composite parent, int style, Item item,
+ boolean cacheImmediately) throws RepositoryException {
+ super(parent, style, item, cacheImmediately);
+ }
+
+ @Override
+ public Item getItem() throws RepositoryException {
+ return getNode();
+ }
+
+ // Experimental, remove
+ public void setMouseListener(MouseListener mouseListener) {
+ super.setMouseListener(mouseListener);
+
+ for (Text txt : texts)
+ txt.addMouseListener(mouseListener);
+
+ }
+
+ @Override
+ protected Control createControl(Composite box, String style) {
+ if (isEditing())
+ return createEditLayout(box, style);
+ else
+ return createROLayout(box, style);
+ }
+
+ protected Composite createROLayout(Composite parent, String style) {
+ Composite body = new Composite(parent, SWT.NO_FOCUS);
+ body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ GridLayout layout = new GridLayout(2, false);
+ body.setLayout(layout);
+
+ createTexts(body, UserStyles.USER_FORM_TEXT);
+ CmsUtils.style(body, UserStyles.USER_FORM_TEXT);
+ return body;
+ }
+
+ private void createTexts(Composite parent, String style) {
+ texts = new ArrayList<Text>();
+ texts.add(createLT(parent, style, "Displayed Name", Property.JCR_TITLE));
+ texts.add(createLT(parent, style, "First name",
+ ArgeoNames.ARGEO_FIRST_NAME));
+ texts.add(createLT(parent, style, "Last name",
+ ArgeoNames.ARGEO_LAST_NAME));
+ texts.add(createLT(parent, style, "Email",
+ ArgeoNames.ARGEO_PRIMARY_EMAIL));
+ texts.add(createLMT(parent, style, "Description",
+ Property.JCR_DESCRIPTION));
+ }
+
+ protected Composite createEditLayout(Composite parent, String style) {
+ Composite body = new Composite(parent, SWT.NO_FOCUS);
+ GridLayout layout = new GridLayout(2, false);
+ body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ body.setLayout(layout);
+
+ createTexts(body, UserStyles.USER_FORM_TEXT);
+
+ for (Text txt : texts)
+ txt.addFocusListener(this);
+ CmsUtils.style(body, UserStyles.USER_FORM_TEXT);
+ return body;
+ }
+
+ void refresh() {
+ for (Text txt : texts) {
+ txt.setText(get(getNode(), (String) txt.getData(KEY_PROP_NAME)));
+ txt.setEditable(isEditing());
+ }
+ }
+
+ // THE LISTENER
+ @Override
+ public void focusGained(FocusEvent e) {
+ // Do nothing
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+ // Save change if needed
+ Text text = (Text) e.getSource();
+ set(getNode(), (String) text.getData(KEY_PROP_NAME), text.getText());
+ }
+
+ // HELPERS
+ /** Creates label and text. */
+ protected Text createLT(Composite body, String style, String label,
+ String propName) {
+ Label lbl = new Label(body, SWT.NONE);
+ lbl.setText(label);
+ lbl.setFont(EclipseUiUtils.getBoldFont(body));
+ lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
+ Text text = new Text(body, SWT.BORDER);
+ text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ CmsUtils.style(text, style);
+ text.setData(KEY_PROP_NAME, propName);
+ return text;
+ }
+
+ /** Creates label and multiline text. */
+ protected Text createLMT(Composite body, String style, String label,
+ String propName) {
+ Label lbl = new Label(body, SWT.NONE);
+ lbl.setText(label);
+ lbl.setFont(EclipseUiUtils.getBoldFont(body));
+ GridData gd = new GridData(SWT.RIGHT, SWT.TOP, false, false);
+ gd.verticalIndent = 0;
+ lbl.setLayoutData(gd);
+ Text text = new Text(body, SWT.BORDER | SWT.MULTI | SWT.WRAP);
+ gd = new GridData(SWT.FILL, SWT.CENTER, true, true);
+ gd.heightHint = 100;
+ text.setLayoutData(gd);
+ CmsUtils.style(text, style);
+ text.setData(KEY_PROP_NAME, propName);
+ return text;
+ }
+
+ /**
+ * Concisely get the string value of a property. Returns an empty String
+ * rather than null if this node doesn't have this property or if the
+ * corresponding property is an empty string.
+ */
+ private String get(Node node, String propertyName) {
+ try {
+ if (!node.hasProperty(propertyName))
+ return "";
+ else
+ return node.getProperty(propertyName).getString();
+ } catch (RepositoryException e) {
+ throw new ArgeoException("Cannot get property " + propertyName
+ + " of " + node, e);
+ }
+ }
+
+ private boolean set(Node node, String propName, String value) {
+ try {
+ if ("".equals(value)
+ && (!node.hasProperty(propName) || node
+ .hasProperty(propName)
+ && "".equals(node.getProperty(propName).getString())))
+ return false;
+ else if (node.hasProperty(propName)
+ && node.getProperty(propName).getString()
+ .equals((String) value))
+ return false;
+ else {
+ node.setProperty(propName, (String) value);
+ node.getSession().save();
+ return true;
+ }
+ } catch (RepositoryException e) {
+ throw new ArgeoException("Cannot property " + propName + " on "
+ + node + " with value " + value, e);
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.users;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Item;
+import javax.jcr.RepositoryException;
+
+import org.argeo.ArgeoException;
+import org.argeo.cms.CmsUtils;
+import org.argeo.cms.viewers.EditablePart;
+import org.argeo.cms.viewers.NodePart;
+import org.argeo.cms.widgets.StyledControl;
+import org.argeo.jcr.ArgeoNames;
+import org.argeo.security.UserAdminService;
+import org.argeo.security.jcr.JcrSecurityModel;
+import org.argeo.security.jcr.JcrUserDetails;
+import org.eclipse.jface.viewers.CheckStateChangedEvent;
+import org.eclipse.jface.viewers.CheckboxTableViewer;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ICheckStateListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.FocusEvent;
+import org.eclipse.swt.events.FocusListener;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableColumn;
+import org.eclipse.swt.widgets.Text;
+import org.springframework.security.GrantedAuthority;
+
+/** Display a single user main info once it has been created. */
+public class UserRolesPart extends StyledControl implements EditablePart,
+ NodePart, FocusListener {
+
+ // A static list of supported properties.
+ private List<Text> texts;
+ private final static String KEY_PROP_NAME = "jcr:propertyName";
+
+ private CheckboxTableViewer rolesViewer;
+ private JcrUserDetails userDetails;
+ private UserAdminService userAdminService;
+ private List<String> roles;
+
+ // FIXME
+ // private final Image checked;
+
+ // TODO implement to provide user creation ability for anonymous user?
+ // public UserPart(Composite parent, int swtStyle) {
+ // super(parent, swtStyle);
+ // }
+
+ public UserRolesPart(Composite parent, int style, Item item,
+ UserAdminService userAdminService, JcrSecurityModel jcrSecurityModel)
+ throws RepositoryException {
+ this(parent, style, item, true);
+ }
+
+ public UserRolesPart(Composite parent, int style, Item item,
+ boolean cacheImmediately) throws RepositoryException {
+ super(parent, style, item, cacheImmediately);
+
+ // checked = new Image(parent, imageData);
+
+ }
+
+ @Override
+ public Item getItem() throws RepositoryException {
+ return getNode();
+ }
+
+ // Experimental, remove
+ public void setMouseListener(MouseListener mouseListener) {
+ super.setMouseListener(mouseListener);
+
+ for (Text txt : texts)
+ txt.addMouseListener(mouseListener);
+
+ }
+
+ @Override
+ protected Control createControl(Composite box, String style) {
+ Table table = new Table(box, SWT.CHECK | SWT.MULTI | SWT.H_SCROLL
+ | SWT.V_SCROLL);
+ table.setLinesVisible(true);
+ table.setHeaderVisible(false);
+ CmsUtils.style(table, style);
+
+ rolesViewer = new CheckboxTableViewer(table);
+
+ TableViewerColumn column;
+
+ // check column
+ // TableViewerColumn column = createTableViewerColumn(rolesViewer,
+ // "checked", 20);
+ // column.setLabelProvider(new ColumnLabelProvider() {
+ // public String getText(Object element) {
+ // return null;
+ // }
+
+ // public Image getImage(Object element) {
+ // String role = element.toString();
+ // if (roles.contains(role)) {
+ //
+ // return ROLE_CHECKED;
+ // } else {
+ // return null;
+ // }
+ //
+ // }
+ // );
+ // column.setEditingSupport(new RoleEditingSupport(rolesViewer, part));
+
+ // role column
+ column = createTableViewerColumn(rolesViewer, "Role", 400);
+ column.setLabelProvider(new ColumnLabelProvider() {
+ private static final long serialVersionUID = -7334412925967366255L;
+
+ public String getText(Object element) {
+ return element.toString();
+ }
+ });
+ rolesViewer.setContentProvider(new RolesContentProvider());
+ rolesViewer.setInput(userAdminService.listEditableRoles().toArray());
+
+ rolesViewer.addCheckStateListener(new ICheckStateListener() {
+
+ @Override
+ public void checkStateChanged(CheckStateChangedEvent event) {
+ String name = (String) event.getElement();
+ boolean contained = roles.contains(name);
+ boolean checked = event.getChecked();
+ if (checked != contained) {
+ if (contained)
+ roles.add(name);
+ else
+ roles.remove(name);
+ userDetails = userDetails.cloneWithNewRoles(roles);
+ userAdminService.updateUser(userDetails);
+ }
+ }
+ });
+ return table;
+ }
+
+ // void refresh() {
+ // for (Text txt : texts) {
+ // }
+ // }
+
+ // THE LISTENER
+ @Override
+ public void focusGained(FocusEvent e) {
+ // Do nothing
+ }
+
+ @Override
+ public void focusLost(FocusEvent e) {
+ // Save change if needed
+ // Text text = (Text) e.getSource();
+ }
+
+ // private final static Image ROLE_CHECKED = SecurityAdminPlugin
+ // .getImageDescriptor("icons/security.gif").createImage();
+
+ public void setUserAdminService(UserAdminService userAdminService) {
+ this.userAdminService = userAdminService;
+
+ try {
+ String username = getNode().getProperty(ArgeoNames.ARGEO_USER_ID)
+ .getString();
+ // ;
+
+ if (userAdminService.userExists(username)) {
+ JcrUserDetails userDetails = (JcrUserDetails) userAdminService
+ .loadUserByUsername(username);
+ setUserDetails(userDetails);
+ }
+ } catch (Exception e) {
+ throw new ArgeoException("Cannot retrieve userDetails for "// +
+ // username
+ , e);
+ }
+
+ }
+
+ public void setUserDetails(JcrUserDetails userDetails) {
+ this.userDetails = userDetails;
+
+ this.roles = new ArrayList<String>();
+ for (GrantedAuthority ga : userDetails.getAuthorities())
+ roles.add(ga.getAuthority());
+ if (rolesViewer != null)
+ rolesViewer.refresh();
+ }
+
+ protected TableViewerColumn createTableViewerColumn(TableViewer viewer,
+ String title, int bound) {
+ final TableViewerColumn viewerColumn = new TableViewerColumn(viewer,
+ SWT.NONE);
+ final TableColumn column = viewerColumn.getColumn();
+ column.setText(title);
+ column.setWidth(bound);
+ column.setResizable(true);
+ column.setMoveable(true);
+ return viewerColumn;
+
+ }
+
+ public List<String> getRoles() {
+ return roles;
+ }
+
+ public void refresh() {
+
+ // return roles.toArray();
+ rolesViewer.setCheckedElements(roles.toArray()); // setSelection(1);
+ // rolesViewer.setInput(roles);
+ rolesViewer.refresh();
+ }
+
+ private class RolesContentProvider implements IStructuredContentProvider {
+ private static final long serialVersionUID = 4119915828862214310L;
+
+ public Object[] getElements(Object inputElement) {
+ return userAdminService.listEditableRoles().toArray();
+ }
+
+ public void dispose() {
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ viewer.refresh();
+ }
+ }
+
+ // /** Select the columns by editing the checkbox in the first column */
+ // class RoleEditingSupport extends EditingSupport {
+ //
+ // private final TableViewer viewer;
+ //
+ // public RoleEditingSupport(TableViewer viewer) {
+ // super(viewer);
+ // this.viewer = viewer;
+ // }
+ //
+ // @Override
+ // protected CellEditor getCellEditor(Object element) {
+ // return new CheckboxCellEditor(null, SWT.CHECK | SWT.READ_ONLY);
+ //
+ // }
+ //
+ // @Override
+ // protected boolean canEdit(Object element) {
+ // return true;
+ // }
+ //
+ // @Override
+ // protected Object getValue(Object element) {
+ // String role = element.toString();
+ // return roles.contains(role);
+ //
+ // }
+ //
+ // @Override
+ // protected void setValue(Object element, Object value) {
+ // Boolean inRole = (Boolean) value;
+ // String role = element.toString();
+ // if (inRole && !roles.contains(role)) {
+ // roles.add(role);
+ // } else if (!inRole && roles.contains(role)) {
+ // roles.remove(role);
+ // }
+ // viewer.refresh();
+ // }
+ // }
+
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.users;
+
+/** Some tries with the style */
+public interface UserStyles {
+
+ /** A text in a form */
+ public final static String USER_FORM_TEXT = "user_form_text";
+
+ public final static String USER_FORM_TEXT_ALT = "user_form_text_alt";
+}
\ No newline at end of file
--- /dev/null
+package org.argeo.cms.users;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.argeo.cms.CmsEditable;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.CmsUtils;
+import org.argeo.cms.viewers.AbstractPageViewer;
+import org.argeo.cms.viewers.EditablePart;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+public class UserViewer extends AbstractPageViewer {
+ private static final long serialVersionUID = -717973369525981931L;
+ private UserPart userPart;
+
+ public UserViewer(Composite parent, int style, Node userNode,
+ CmsEditable cmsEditable) throws RepositoryException {
+ this(new UserPart(parent, SWT.NO_BACKGROUND, userNode), style,
+ userNode, cmsEditable);
+ }
+
+ private UserViewer(UserPart userPart, int style, Node userNode,
+ CmsEditable cmsEditable) throws RepositoryException {
+ super(userPart, style, cmsEditable);
+ this.userPart = userPart;
+ userPart.createControl(userPart,"cms_test");
+ userPart.setStyle("cms_test");
+ refresh();
+ userPart.setLayoutData(CmsUtils.fillWidth());
+ userPart.setMouseListener(getMouseListener());
+
+ // Add other parts
+// userRolesPart.createControl(userPart,"cms_test");
+// userPart.setStyle("cms_test");
+// refresh();
+// userPart.setLayoutData(CmsUtils.fillWidth());
+// userPart.setMouseListener(getMouseListener());
+
+
+ }
+
+ // private JcrComposite createParents(Composite parent, Node userNode)
+ // throws RepositoryException {
+ // this.parent = ;
+ // return this.parent;
+ // }
+
+ @Override
+ public Control getControl() {
+ return userPart;
+ }
+
+ // MOUSE LISTENER
+ @Override
+ protected MouseListener createMouseListener() {
+ return new ML();
+ }
+
+ private class ML extends MouseAdapter {
+ private static final long serialVersionUID = 8526890859876770905L;
+
+ @Override
+ public void mouseDoubleClick(MouseEvent e) {
+ if (e.button == 1) {
+ Control source = (Control) e.getSource();
+ if (getCmsEditable().canEdit()) {
+ getCmsEditable().startEditing();
+ EditablePart composite = findDataParent(source);
+ Point point = new Point(e.x, e.y);
+ edit(composite, source.toDisplay(point));
+ }
+ }
+ }
+ }
+
+ protected void updateContent(EditablePart part) throws RepositoryException {
+ if (part instanceof UserPart)
+ ((UserPart) part).refresh();
+ }
+
+
+ private EditablePart findDataParent(Control parent) {
+ if (parent instanceof EditablePart) {
+ return (EditablePart) parent;
+ }
+ if (parent.getParent() != null)
+ return findDataParent(parent.getParent());
+ else
+ throw new CmsException("No data parent found");
+ }
+
+ protected void refresh(Control control) throws RepositoryException {
+ if (control instanceof UserPart)
+ ((UserPart) control).refresh();
+ }
+
+}
--- /dev/null
+package org.argeo.cms.users;
+
+import java.util.Observable;
+import java.util.Observer;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.ArgeoException;
+import org.argeo.cms.CmsEditable;
+import org.argeo.cms.CmsException;
+import org.argeo.cms.CmsUtils;
+import org.argeo.cms.viewers.EditablePart;
+import org.argeo.cms.viewers.JcrVersionCmsEditable;
+import org.eclipse.jface.viewers.ContentViewer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.events.MouseAdapter;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Widget;
+
+/** Manage edition of the users */
+public class UserViewerOld extends ContentViewer implements Observer {
+ private static final long serialVersionUID = -5055220955004863645L;
+
+ private final static Log log = LogFactory.getLog(UserViewerOld.class);
+
+ // private UserPart userPart = new UserPart();
+
+ private CmsEditable cmsEditable;
+ private Node currentDisplayed;
+
+ /** The basis for the layouts, typically the body of a ScrolledPage. */
+ private final Composite page;
+
+ private MouseListener mouseListener;
+
+ private EditablePart edited;
+ private ISelection selection = StructuredSelection.EMPTY;
+
+ protected UserViewerOld(Composite composite) {
+ page = composite;
+ }
+
+ void setDisplayedUser(Node node) {
+ try {
+
+ if (!hasChanged(node))
+ return;
+
+ CmsUtils.clear(page);
+ // userPart.createUi(page, node);
+
+ page.layout();
+ page.getParent().layout();
+
+ // update
+ cmsEditable = new JcrVersionCmsEditable(node);
+
+ if (this.cmsEditable instanceof Observable)
+ ((Observable) this.cmsEditable).addObserver(this);
+ // // if (cmsEditable.canEdit()) {
+ // // mouseListener = createMouseListener();
+ // // refresh();
+ // // }
+ } catch (RepositoryException re) {
+ throw new ArgeoException("Unable to display " + node, re);
+ }
+ }
+
+ private boolean hasChanged(Node node) throws RepositoryException {
+ if (currentDisplayed == null && node == null)
+ return false;
+ else if (currentDisplayed == null || node == null)
+ return true;
+ else
+ return node.getIdentifier()
+ .equals(currentDisplayed.getIdentifier());
+ }
+
+ /** Create (retrieve) the MouseListener to use. */
+ protected MouseListener createMouseListener() {
+ return new MouseAdapter() {
+ private static final long serialVersionUID = 1L;
+ };
+ }
+
+ @Override
+ public void update(Observable o, Object arg) {
+ if (o == cmsEditable)
+ editingStateChanged(cmsEditable);
+ }
+
+ /** To be overridden in order to provide the actual refresh */
+ protected void refresh(Control control) throws RepositoryException {
+ }
+
+ /** To be overridden.Save the edited part. */
+ protected void save(EditablePart part) throws RepositoryException {
+ }
+
+ /** Prepare the edited part */
+ protected void prepare(EditablePart part, Object caretPosition) {
+ }
+
+ /** Notified when the editing state changed. Does nothing, to be overridden */
+ protected void editingStateChanged(CmsEditable cmsEditable) {
+ }
+
+ @Override
+ public Control getControl() {
+ return null;
+ }
+
+ @Override
+ public void refresh() {
+ try {
+ // if (cmsEditable.canEdit() && !readOnly)
+ // mouseListener = createMouseListener();
+ // else
+ // mouseListener = null;
+ refresh(getControl());
+ layout(getControl());
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot refresh", e);
+ }
+ }
+
+ @Override
+ public void setSelection(ISelection selection, boolean reveal) {
+ this.selection = selection;
+ }
+
+ protected void updateContent(EditablePart part) throws RepositoryException {
+ }
+
+ // LOW LEVEL EDITION
+ protected void edit(EditablePart part, Object caretPosition) {
+ try {
+ if (edited == part)
+ return;
+
+ if (edited != null && edited != part)
+ stopEditing(true);
+
+ part.startEditing();
+ updateContent(part);
+ prepare(part, caretPosition);
+ edited = part;
+ layout(part.getControl());
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot edit " + part, e);
+ }
+ }
+
+ private void stopEditing(Boolean save) throws RepositoryException {
+ if (edited instanceof Widget && ((Widget) edited).isDisposed()) {
+ edited = null;
+ return;
+ }
+
+ assert edited != null;
+ if (edited == null) {
+ if (log.isTraceEnabled())
+ log.warn("Told to stop editing while not editing anything");
+ return;
+ }
+
+ if (save)
+ save(edited);
+
+ edited.stopEditing();
+ updateContent(edited);
+ layout(((EditablePart) edited).getControl());
+ edited = null;
+ }
+
+ // METHODS AVAILABLE TO EXTENDING CLASSES
+ protected void saveEdit() {
+ try {
+ if (edited != null)
+ stopEditing(true);
+ } catch (RepositoryException e) {
+ throw new CmsException("Cannot stop editing", e);
+ }
+ }
+
+ protected void cancelEdit() {
+ try {
+ if (edited != null)
+ stopEditing(false);
+ } catch (RepositoryException e) {
+
+ throw new CmsException("Cannot cancel editing", e);
+ }
+ }
+
+ /** Layout this controls from the related base page. */
+ public void layout(Control... controls) {
+ page.layout(controls);
+ }
+
+ // UTILITIES
+ /** Check whether the edited part is in a proper state */
+ protected void checkEdited() {
+ if (edited == null || (edited instanceof Widget)
+ && ((Widget) edited).isDisposed())
+ throw new CmsException(
+ "Edited should not be null or disposed at this stage");
+ }
+
+ // GETTERS / SETTERS
+ protected EditablePart getEdited() {
+ return edited;
+ }
+
+ public MouseListener getMouseListener() {
+ return mouseListener;
+ }
+
+ public CmsEditable getCmsEditable() {
+ return cmsEditable;
+ }
+
+ @Override
+ public ISelection getSelection() {
+ return selection;
+ }
+}
\ No newline at end of file
import javax.jcr.security.AccessControlManager;
import javax.jcr.security.Privilege;
+import org.argeo.ArgeoException;
import org.argeo.cms.CmsUiProvider;
import org.argeo.cms.CmsUtils;
import org.argeo.cms.maintenance.NonAdminPage;
+import org.argeo.eclipse.ui.dialogs.UserCreationWizard;
import org.argeo.eclipse.ui.parts.UsersTable;
import org.argeo.jcr.JcrUtils;
+import org.argeo.security.UserAdminService;
+import org.argeo.security.jcr.JcrSecurityModel;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
+/**
+ * Simple page to manage users of a given repository. We still rely on Argeo
+ * model; with user stored in the main workspace
+ */
public class Users implements CmsUiProvider {
+ // Enable user CRUD // INJECTED
+ private UserAdminService userAdminService;
+ private JcrSecurityModel jcrSecurityModel;
+ private String userWkspName;
+
+ // Local UI Providers
NonAdminPage nap = new NonAdminPage();
+ UserPage userPage = new UserPage();
+ // Manage authorization
@Override
public Control createUi(Composite parent, Node context)
throws RepositoryException {
-
if (isAdmin(context)) {
Session session = context.getSession().getRepository()
- .login("main");
- return createUsersTable(parent, session);
+ .login(userWkspName);
+ return createMainLayout(parent, session);
} else
nap.createUi(parent, context);
return null;
+ }
+
+ // Main layout
+ // Left: User Table - Right User Details Edition
+ private Control createMainLayout(Composite parent, final Session session)
+ throws RepositoryException {
+
+ Composite layoutCmp = new Composite(parent, SWT.NO_FOCUS);
+ layoutCmp.setLayoutData(CmsUtils.fillAll());
+ layoutCmp
+ .setLayout(CmsUtils.noSpaceGridLayout(new GridLayout(2, true)));
+
+ Composite left = new Composite(layoutCmp, SWT.NO_FOCUS);
+ left.setLayoutData(CmsUtils.fillAll());
+ UsersTable table = createUsersTable(left, session);
+
+ final Composite right = new Composite(layoutCmp, SWT.NO_FOCUS);
+ right.setLayoutData(CmsUtils.fillAll());
+ // Composite innerPage = createUserPage(right);
+ // final UserViewerOld userViewer = new UserViewerOld(innerPage);
+ final TableViewer viewer = table.getTableViewer();
+ viewer.addSelectionChangedListener(new ISelectionChangedListener() {
+
+ @Override
+ public void selectionChanged(SelectionChangedEvent event) {
+ IStructuredSelection selection = (IStructuredSelection) viewer
+ .getSelection();
+ if (selection.isEmpty()) {
+ // Should we clean the right column?
+ return;
+ } else {
+ Node context = (Node) selection.getFirstElement();
+ try {
+ CmsUtils.clear(right);
+ userPage.createUi(right, context);
+ right.layout();
+ right.getParent().layout();
+ } catch (RepositoryException e) {
+ e.printStackTrace();
+ throw new ArgeoException("unable to create "
+ + "editor for user " + context, e);
+ }
+ }
+ }
+ });
+ return left;
}
- private Control createUsersTable(Composite parent, final Session session)
+ private UsersTable createUsersTable(Composite parent, final Session session)
throws RepositoryException {
+ parent.setLayout(CmsUtils.noSpaceGridLayout());
+
+ // Add user CRUD buttons
+ Composite buttonCmp = new Composite(parent, SWT.NO_FOCUS);
+ buttonCmp.setLayoutData(CmsUtils.fillWidth());
+ buttonCmp.setLayout(new GridLayout(2, false));
+ // Delete
+ final Button deleteBtn = new Button(buttonCmp, SWT.PUSH);
+ deleteBtn.setText("Delete selected");
+ // Add
+ final Button addBtn = new Button(buttonCmp, SWT.PUSH);
+ addBtn.setText("Create");
+ addBtn.addSelectionListener(new SelectionListener() {
+ private static final long serialVersionUID = 9214984636836267786L;
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ UserCreationWizard newUserWizard = new UserCreationWizard(
+ session, userAdminService, jcrSecurityModel);
+ WizardDialog dialog = new WizardDialog(addBtn.getShell(),
+ newUserWizard);
+ dialog.open();
+ // TODO refresh list if user has been created
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ });
+
// Create the composite that displays the list and a filter
UsersTable userTableCmp = new UsersTable(parent, SWT.NO_FOCUS, session);
userTableCmp.populate(true, false);
-
userTableCmp.setLayoutData(CmsUtils.fillAll());
-
userTableCmp.addDisposeListener(new DisposeListener() {
private static final long serialVersionUID = -8854052549807709846L;
return userTableCmp;
}
+ // protected Composite createUserPage(Composite parent) {
+ // parent.setLayout(CmsUtils.noSpaceGridLayout());
+ // ScrolledPage scrolled = new ScrolledPage(parent, SWT.NONE);
+ // scrolled.setLayoutData(CmsUtils.fillAll());
+ // scrolled.setLayout(CmsUtils.noSpaceGridLayout());
+ // // TODO manage style
+ // // CmsUtils.style(scrolled, "maintenance_user_form");
+ //
+ // Composite page = new Composite(scrolled, SWT.NONE);
+ // page.setLayout(CmsUtils.noSpaceGridLayout());
+ // page.setBackgroundMode(SWT.INHERIT_NONE);
+ //
+ // return page;
+ // }
+
private boolean isAdmin(Node node) throws RepositoryException {
- // FIXME clean this check one new user management policy has been
+ // FIXME clean this once new user management policy has been
// implemented.
AccessControlManager acm = node.getSession().getAccessControlManager();
Privilege[] privs = new Privilege[1];
// }
// }
-}
+ /* DEPENDENCY INJECTION */
+ public void setWorkspaceName(String workspaceName) {
+ this.userWkspName = workspaceName;
+ }
+
+ public void setUserAdminService(UserAdminService userAdminService) {
+ this.userAdminService = userAdminService;
+ userPage.setUserAdminService(userAdminService);
+ }
+
+ public void setJcrSecurityModel(JcrSecurityModel jcrSecurityModel) {
+ this.jcrSecurityModel = jcrSecurityModel;
+ userPage.setJcrSecurityModel(jcrSecurityModel);
+ }
+}
\ No newline at end of file
import org.apache.commons.logging.LogFactory;
import org.argeo.cms.CmsEditable;
import org.argeo.cms.CmsException;
+import org.argeo.cms.widgets.JcrComposite;
import org.argeo.cms.widgets.ScrolledPage;
import org.eclipse.jface.viewers.ContentViewer;
import org.eclipse.jface.viewers.ISelection;
private EditablePart edited;
private ISelection selection = StructuredSelection.EMPTY;
+ // FIXME Added by BSinou to manage non-section Composite.
+ // Is it the correct method?
+ protected AbstractPageViewer(Composite parent, int style,
+ CmsEditable cmsEditable) {
+ // read only at UI level
+ readOnly = SWT.READ_ONLY == (style & SWT.READ_ONLY);
+
+ this.cmsEditable = cmsEditable == null ? CmsEditable.NON_EDITABLE
+ : cmsEditable;
+ if (this.cmsEditable instanceof Observable)
+ ((Observable) this.cmsEditable).addObserver(this);
+
+ if (cmsEditable.canEdit()) {
+ mouseListener = createMouseListener();
+ }
+ page = findPage(parent);
+ }
+
protected AbstractPageViewer(Section parent, int style,
CmsEditable cmsEditable) {
// read only at UI level
org.osgi.util.tracker;version="[1.4,2)",\
org.springframework.beans.factory,\
org.springframework.core.io.support,\
+ org.springframework.dao,\
*
# Was:
<artifactId>org.springframework.context</artifactId>
</dependency>
+ <!-- Base security -->
+ <dependency>
+ <groupId>org.argeo.commons</groupId>
+ <artifactId>org.argeo.security.core</artifactId>
+ <version>2.1.12-SNAPSHOT</version>
+ </dependency>
+
+
<!-- Others -->
<dependency>
<groupId>org.argeo.tp</groupId>
--- /dev/null
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.eclipse.ui.dialogs;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.ArgeoException;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.jcr.ArgeoNames;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.jcr.UserJcrUtils;
+import org.argeo.security.UserAdminService;
+import org.argeo.security.jcr.JcrSecurityModel;
+import org.argeo.security.jcr.JcrUserDetails;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.wizard.Wizard;
+import org.eclipse.jface.wizard.WizardPage;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+import org.springframework.security.GrantedAuthority;
+import org.springframework.security.userdetails.UserDetails;
+import org.springframework.security.userdetails.UsernameNotFoundException;
+
+/** Wizard to create a new user */
+public class UserCreationWizard extends Wizard {
+ private final static Log log = LogFactory.getLog(UserCreationWizard.class);
+ private Session session;
+ private UserAdminService userAdminService;
+ private JcrSecurityModel jcrSecurityModel;
+
+ // pages
+ private MainUserInfoWizardPage mainUserInfo;
+
+ public UserCreationWizard(Session session, UserAdminService userAdminService,
+ JcrSecurityModel jcrSecurityModel) {
+ this.session = session;
+ this.userAdminService = userAdminService;
+ this.jcrSecurityModel = jcrSecurityModel;
+ }
+
+ @Override
+ public void addPages() {
+ mainUserInfo = new MainUserInfoWizardPage(userAdminService);
+ addPage(mainUserInfo);
+ }
+
+ @Override
+ public boolean performFinish() {
+ if (!canFinish())
+ return false;
+
+ String username = mainUserInfo.getUsername();
+ try {
+ Node userProfile = jcrSecurityModel.sync(session, username, null);
+ session.getWorkspace().getVersionManager()
+ .checkout(userProfile.getPath());
+ mainUserInfo.mapToProfileNode(userProfile);
+ String password = mainUserInfo.getPassword();
+ // TODO add roles
+ JcrUserDetails jcrUserDetails = new JcrUserDetails(userProfile,
+ password, new GrantedAuthority[0]);
+ session.save();
+ session.getWorkspace().getVersionManager()
+ .checkin(userProfile.getPath());
+ userAdminService.createUser(jcrUserDetails);
+ return true;
+ } catch (Exception e) {
+ JcrUtils.discardQuietly(session);
+ Node userHome = UserJcrUtils.getUserHome(session, username);
+ if (userHome != null) {
+ try {
+ userHome.remove();
+ session.save();
+ } catch (RepositoryException e1) {
+ JcrUtils.discardQuietly(session);
+ log.warn("Error when trying to clean up failed new user "
+ + username, e1);
+ }
+ }
+ MessageDialog.openError(getShell(), "Eroor",
+ "Cannot create new user " + username);
+ return false;
+ }
+ }
+
+ /** First page, collect all main info and check their validity */
+ protected class MainUserInfoWizardPage extends WizardPage implements
+ ModifyListener, ArgeoNames {
+ private static final long serialVersionUID = -3367329974808698649L;
+ private Text username, firstName, lastName, primaryEmail, password1,
+ password2;
+ private UserAdminService userAdminService;
+
+ public MainUserInfoWizardPage(UserAdminService userAdminService) {
+ super("Main");
+ this.userAdminService = userAdminService;
+ setTitle("Required Information");
+ }
+
+ @Override
+ public void createControl(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setLayout(new GridLayout(2, false));
+ username = EclipseUiUtils.createGridLT(composite, "Username", this);
+ primaryEmail = EclipseUiUtils
+ .createGridLT(composite, "Email", this);
+ firstName = EclipseUiUtils.createGridLT(composite, "First name",
+ this);
+ lastName = EclipseUiUtils
+ .createGridLT(composite, "Last name", this);
+ password1 = EclipseUiUtils
+ .createGridLP(composite, "Password", this);
+ password2 = EclipseUiUtils.createGridLP(composite,
+ "Repeat password", this);
+ setControl(composite);
+
+ // Initialize buttons
+ setPageComplete(false);
+ getContainer().updateButtons();
+ }
+
+ @Override
+ public void modifyText(ModifyEvent event) {
+ String message = checkComplete();
+ if (message != null) {
+ setMessage(message, WizardPage.ERROR);
+ setPageComplete(false);
+ } else {
+ setMessage("Complete", WizardPage.INFORMATION);
+ setPageComplete(true);
+ }
+ getContainer().updateButtons();
+ }
+
+ /** @return error message or null if complete */
+ protected String checkComplete() {
+ // if
+ // (!username.getText().matches(UserAdminService.USERNAME_PATTERN))
+ // return
+ // "Wrong user name format, should be lower case, between 3 and 64 characters with only '_' an '@' as acceptable special character.";
+
+ if (username.getText().trim().equals(""))
+ return "User name must not be empty";
+
+ try {
+ UserDetails userDetails = userAdminService
+ .loadUserByUsername(username.getText());
+ return "User " + userDetails.getUsername() + " already exists";
+ } catch (UsernameNotFoundException e) {
+ // silent
+ }
+ if (!primaryEmail.getText().matches(UserAdminService.EMAIL_PATTERN))
+ return "Not a valid email address";
+ if (firstName.getText().trim().equals(""))
+ return "Specify a first name";
+ if (lastName.getText().trim().equals(""))
+ return "Specify a last name";
+ if (password1.getText().trim().equals(""))
+ return "Specify a password";
+ if (password2.getText().trim().equals(""))
+ return "Repeat the password";
+ if (!password2.getText().equals(password1.getText()))
+ return "Passwords are different";
+ return null;
+ }
+
+ public String getUsername() {
+ return username.getText();
+ }
+
+ public String getPassword() {
+ return password1.getText();
+ }
+
+ public void mapToProfileNode(Node up) {
+ try {
+ up.setProperty(ARGEO_PRIMARY_EMAIL, primaryEmail.getText());
+ up.setProperty(ARGEO_FIRST_NAME, firstName.getText());
+ up.setProperty(ARGEO_LAST_NAME, lastName.getText());
+
+ // derived values
+ // TODO add wizard pages to do it
+ up.setProperty(Property.JCR_TITLE, firstName.getText() + " "
+ + lastName.getText());
+ up.setProperty(Property.JCR_DESCRIPTION, "");
+ } catch (RepositoryException e) {
+ throw new ArgeoException("Cannot map to " + up, e);
+ }
+ }
+ }
+}
\ No newline at end of file
<artifactId>org.eclipse.osgi</artifactId>
</dependency>
+ <!-- Generic Eclipse Utilities -->
+ <dependency>
+ <groupId>org.argeo.commons</groupId>
+ <artifactId>org.argeo.eclipse.ui.workbench</artifactId>
+ <version>2.1.12-SNAPSHOT</version>
+ </dependency>
+
<!-- RAP only dependency, needed at compile time -->
<dependency>
<groupId>org.argeo.commons</groupId>
public class MainUserInfoWizardPage extends WizardPage implements
ModifyListener, ArgeoNames {
+ private static final long serialVersionUID = -3367329974808698649L;
private Text username, firstName, lastName, primaryEmail, password1,
password2;
private UserAdminService userAdminService;