--- /dev/null
+package org.argeo.app.api;
+
+/** A range of numerical IDs (typically numerical uid or gid). */
+public class IdRange {
+
+ private final long min;
+ private final long max;
+
+ public IdRange(long min, long max) {
+ this.min = min;
+ this.max = max;
+ }
+
+ public IdRange(long minPow10) {
+ this(minPow10, maxFromMinPow10(minPow10));
+ }
+
+ public long getMin() {
+ return min;
+ }
+
+ public long getMax() {
+ return max;
+ }
+
+ private static long maxFromMinPow10(long minPow10) {
+ if ((minPow10 % 100) != 0) {
+ throw new IllegalArgumentException(minPow10 + " must at least ends with two zeroes");
+ }
+ int exp = 2;
+ exp: for (int i = exp + 1; i < 10; i++) {
+ if ((minPow10 % pow10(i)) != 0)
+ break exp;
+ exp++;
+ }
+ System.out.println(exp);
+
+ long max = minPow10 + pow10(exp) - 1;
+ return max;
+ }
+
+ /** Power of 10. */
+ private static long pow10(int exp) {
+ if (exp == 0)
+ return 1;
+ else
+ return 10 * pow10(exp - 1);
+ }
+
+ public static void main(String... args) {
+ System.out.println(maxFromMinPow10(100));
+ System.out.println(maxFromMinPow10(78500));
+ System.out.println(maxFromMinPow10(716850000));
+
+// System.out.println(pow10(6));
+// System.out.println(maxFromMinPow10(12));
+// System.out.println(maxFromMinPow10(124));
+// System.out.println(maxFromMinPow10(99814565));
+ }
+}
package org.argeo.app.core;
import java.util.HashSet;
+import java.util.Optional;
import java.util.Set;
import javax.jcr.Node;
import javax.jcr.nodetype.NodeType;
import javax.jcr.security.Privilege;
import javax.security.auth.x500.X500Principal;
+import javax.xml.namespace.QName;
+import org.argeo.api.acr.Content;
import org.argeo.api.cms.CmsConstants;
import org.argeo.api.cms.CmsSession;
import org.argeo.app.api.EntityType;
import org.argeo.jcr.JcrException;
import org.argeo.jcr.JcrUtils;
import org.argeo.util.naming.LdapAttrs;
+import org.argeo.util.naming.LdapObjs;
/** Utilities around the Argeo Suite APIs. */
public class SuiteUtils {
}
}
- /** Singleton. */
- private SuiteUtils() {
-
- }
-
public static Set<String> extractRoles(String[] semiColArr) {
Set<String> res = new HashSet<>();
// TODO factorize and make it more robust
return res;
}
+ synchronized static public long findNextId(Content hierarchyUnit, QName cclass) {
+ if (!hierarchyUnit.hasContentClass(LdapObjs.posixGroup.qName()))
+ throw new IllegalArgumentException(hierarchyUnit + " is not a POSIX group");
+
+ long min = hierarchyUnit.get(LdapAttrs.gidNumber.qName(), Long.class).orElseThrow();
+ long currentMax = 0l;
+ for (Content childHu : hierarchyUnit) {
+ if (!childHu.hasContentClass(LdapObjs.organizationalUnit.qName()))
+ continue;
+ // FIXME filter out functional hierarchy unit
+ for (Content role : childHu) {
+ if (role.hasContentClass(cclass)) {
+
+ if (LdapObjs.posixAccount.qName().equals(cclass)) {
+ Long id = role.get(LdapAttrs.uidNumber.qName(), Long.class).orElseThrow();
+ if (id > currentMax)
+ currentMax = id;
+ }
+ }
+ }
+ }
+ if (currentMax == 0l)
+ return min;
+ return currentMax + 1;
+ }
+
+ /** Singleton. */
+ private SuiteUtils() {
+ }
}
# Geo
map=map
+# Feedback messages
+allFieldsMustBeSet=All fields must be set
+
# Tags
confirmNewTag=Le tag #{0} n'existe pas encore. Voulez-vous le créer?
cannotCreateTag=Le tag #{0} n'existe pas encore et vous n'avez pas les droits pour le créer.
+
+# Feedback messages
+allFieldsMustBeSet=Toutes les données doivent être renseignées
<service>
<provide interface="org.argeo.app.ui.SuiteLayer"/>
</service>
- <reference bind="setEntryArea" cardinality="1..1" interface="org.argeo.cms.ui.CmsUiProvider" name="CmsUiProvider" policy="dynamic" target="(service.pid=argeo.people.ui.peopleEntryArea)"/>
+ <reference bind="setEntryArea" cardinality="1..1" interface="org.argeo.cms.swt.acr.SwtUiProvider" name="CmsUiProvider" policy="dynamic" target="(service.pid=argeo.people.ui.peopleEntryArea)"/>
</scr:component>
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
import org.osgi.framework.wiring.BundleWiring;
/** An app layer based on an entry area and an editor area. */
public class DefaultEditionLayer implements SuiteLayer {
+ private String id;
private SwtUiProvider entryArea;
private SwtUiProvider defaultView;
private SwtUiProvider workArea;
return title;
}
+ @Override
+ public String getId() {
+ return id;
+ }
+
public void init(BundleContext bundleContext, Map<String, Object> properties) {
+ String pid = (String) properties.get(Constants.SERVICE_PID);
+ id = pid;
+
weights = LangUtils.toStringList(properties.get(Property.weights.name()));
startMaximized = properties.containsKey(Property.startMaximized.name())
&& "true".equals(properties.get(Property.startMaximized.name()));
import static org.argeo.api.cms.ux.CmsView.CMS_VIEW_UID_PROPERTY;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
}
}
+// public void addLayer(SuiteLayer layer, Map<String, Object> properties) {
+// if (!properties.containsKey(Constants.SERVICE_PID))
+// throw new IllegalArgumentException("A layer must have an ID");
+// String pid = (String) properties.get(Constants.SERVICE_PID);
+// List<String> types = properties.containsKey(EntityConstants.TYPE)
+// ? LangUtils.toStringList(properties.get(EntityConstants.TYPE))
+// : new ArrayList<>();
+// if (types.isEmpty()) {
+// RankedObject.putIfHigherRank(layersByPid, pid, layer, properties);
+// } else {
+// if (layersByPid.containsKey(pid)) {
+// RankedObject<SuiteLayer> current = layersByPid.get(pid);
+// List<String> currentTypes = current.getProperties().containsKey(EntityConstants.TYPE)
+// ? LangUtils.toStringList(current.getProperties().get(EntityConstants.TYPE))
+// : new ArrayList<>();
+// if (!types.containsAll(currentTypes)) {
+// throw new IllegalArgumentException("Higher-ranked layer " + pid + " contains only types " + types
+// + ", while it must override all " + currentTypes);
+// }
+// }
+// RankedObject.putIfHigherRank(layersByPid, pid, layer, properties);
+// for (String type : types)
+// RankedObject.putIfHigherRank(layersByType, type, layer, properties);
+// }
+// }
+
public void addLayer(SuiteLayer layer, Map<String, Object> properties) {
- if (!properties.containsKey(Constants.SERVICE_PID))
- throw new IllegalArgumentException("A layer must have an ID");
- String pid = (String) properties.get(Constants.SERVICE_PID);
- List<String> types = properties.containsKey(EntityConstants.TYPE)
- ? LangUtils.toStringList(properties.get(EntityConstants.TYPE))
- : new ArrayList<>();
- if (types.isEmpty()) {
- RankedObject.putIfHigherRank(layersByPid, pid, layer, properties);
- } else {
- if (layersByPid.containsKey(pid)) {
- RankedObject<SuiteLayer> current = layersByPid.get(pid);
- List<String> currentTypes = current.getProperties().containsKey(EntityConstants.TYPE)
- ? LangUtils.toStringList(current.getProperties().get(EntityConstants.TYPE))
- : new ArrayList<>();
- if (!types.containsAll(currentTypes)) {
- throw new IllegalArgumentException("Higher-ranked layer " + pid + " contains only types " + types
- + ", while it must override all " + currentTypes);
- }
- }
+ if (properties.containsKey(Constants.SERVICE_PID)) {
+ String pid = (String) properties.get(Constants.SERVICE_PID);
RankedObject.putIfHigherRank(layersByPid, pid, layer, properties);
+ }
+ if (properties.containsKey(EntityConstants.TYPE)) {
+ List<String> types = LangUtils.toStringList(properties.get(EntityConstants.TYPE));
for (String type : types)
RankedObject.putIfHigherRank(layersByType, type, layer, properties);
}
title, icon, weights, startMaximized, singleTab, fixedEntryArea;
}
+ String getId();
+
void view(SwtUiProvider uiProvider, Composite workArea, Content context);
-
+
Content getCurrentContext(Composite workArea);
default void open(SwtUiProvider uiProvider, Composite workArea, Content context) {
// Generic
label, aCustomLabel, description, value, name, primary, add, save, pickup,
// Tag
- confirmNewTag, cannotCreateTag;
+ confirmNewTag, cannotCreateTag,
+ // Feddback messages
+ allFieldsMustBeSet,
+ //
+ ;
}
// TODO make it more robust
for (String layerId : layers.keySet()) {
SuiteLayer l = layers.get(layerId);
- if (layer == l) {
+ if (layer.getId().equals(l.getId())) {
switchToLayer(layerId, context);
+ return;
}
}
throw new IllegalArgumentException("Layer is not registered.");
+++ /dev/null
-package org.argeo.app.ui.dialogs;
-
-import static org.argeo.eclipse.ui.EclipseUiUtils.isEmpty;
-
-import org.argeo.app.ui.SuiteMsg;
-import org.argeo.app.ui.SuiteUiUtils;
-import org.argeo.cms.swt.dialogs.CmsFeedback;
-import org.argeo.cms.swt.widgets.SwtGuidedFormPage;
-import org.argeo.cms.ux.widgets.AbstractGuidedForm;
-import org.argeo.eclipse.ui.EclipseUiUtils;
-import org.argeo.util.directory.HierarchyUnit;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Text;
-
-/** Ask first & last name. Update the passed node on finish */
-public class NewUserWizard extends AbstractGuidedForm {
- // private final static Log log = LogFactory.getLog(NewPersonWizard.class);
-
- // Context
-// private Node person;
- private HierarchyUnit hierarchyUnit;
- // This page widgets
- protected Text lastNameTxt;
- protected Text firstNameTxt;
- // private Button useDistinctDisplayNameBtn;
- // private Text displayNameTxt;
-
- public NewUserWizard(HierarchyUnit hierarchyUnit) {
- this.hierarchyUnit = hierarchyUnit;
- }
-
- @Override
- public void addPages() {
- try {
- MainInfoPage page = new MainInfoPage("Main page");
- addPage(page);
- } catch (Exception e) {
- throw new RuntimeException("Cannot add page to wizard", e);
- }
- setFormTitle(SuiteMsg.personWizardWindowTitle.lead());
- }
-
- /**
- * Called when the user click on 'Finish' in the wizard. The task is then
- * created and the corresponding session saved.
- */
- @Override
- public boolean performFinish() {
- String lastName = lastNameTxt.getText();
- String firstName = firstNameTxt.getText();
- // String displayName = displayNameTxt.getText();
- // boolean useDistinct = useDistinctDisplayNameBtn.getSelection();
- if (EclipseUiUtils.isEmpty(lastName) && EclipseUiUtils.isEmpty(firstName)) {
-// MessageDialog.openError(getShell(), "Non-valid information",
-// "Please enter at least a name that is not empty.");
- CmsFeedback.show("Please enter at least a name that is not empty.");
- return false;
- } else {
-// ConnectJcrUtils.setJcrProperty(person, PEOPLE_LAST_NAME, PropertyType.STRING, lastName);
-// ConnectJcrUtils.setJcrProperty(person, PEOPLE_FIRST_NAME, PropertyType.STRING, firstName);
-// String fullName = firstName + " " + lastName;
-// ConnectJcrUtils.setJcrProperty(person, PEOPLE_DISPLAY_NAME, PropertyType.STRING, fullName);
- return true;
- }
- }
-
- @Override
- public boolean performCancel() {
- return true;
- }
-
- @Override
- public boolean canFinish() {
- String lastName = lastNameTxt.getText();
- String firstName = firstNameTxt.getText();
- if (isEmpty(lastName) && isEmpty(firstName)) {
- return false;
- } else
- return true;
- }
-
- protected class MainInfoPage extends SwtGuidedFormPage {
-
- public MainInfoPage(String pageName) {
- super(pageName);
- setTitle(SuiteMsg.personWizardPageTitle.lead());
- // setMessage("Please enter a last name and/or a first name.");
- }
-
- public void createControl(Composite parent) {
- parent.setLayout(new GridLayout(2, false));
-
- // FirstName
- SuiteUiUtils.createBoldLabel(parent, SuiteMsg.firstName);
- firstNameTxt = new Text(parent, SWT.BORDER);
- // firstNameTxt.setMessage("a first name");
- firstNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-
- // LastName
- SuiteUiUtils.createBoldLabel(parent, SuiteMsg.lastName);
- lastNameTxt = new Text(parent, SWT.BORDER);
- // lastNameTxt.setMessage("a last name");
- lastNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
-
- // Display Name
- // useDistinctDisplayNameBtn = new Button(parent, SWT.CHECK);
- // useDistinctDisplayNameBtn.setText("Define a disting display name");
- // useDistinctDisplayNameBtn.setLayoutData(new GridData(SWT.FILL, SWT.CENTER,
- // true, false, 2, 1));
- //
- // ConnectWorkbenchUtils.createBoldLabel(parent, "Display Name");
- // displayNameTxt = new Text(parent, SWT.BORDER);
- // displayNameTxt.setMessage("an optional display name");
- // displayNameTxt.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
- // false));
- // displayNameTxt.setEnabled(false);
- //
- // useDistinctDisplayNameBtn.addSelectionListener(new SelectionAdapter() {
- // private static final long serialVersionUID = 1L;
- //
- // @Override
- // public void widgetSelected(SelectionEvent e) {
- // displayNameTxt.setEnabled(useDistinctDisplayNameBtn.getSelection());
- // }
- // });
-
- ModifyListener ml = new ModifyListener() {
- private static final long serialVersionUID = -1628130380128946886L;
-
- @Override
- public void modifyText(ModifyEvent event) {
- getView().updateButtons();
- }
- };
-
- firstNameTxt.addModifyListener(ml);
- lastNameTxt.addModifyListener(ml);
- // displayNameTxt.addModifyListener(ml);
-
- // Don't forget this.
- // setControl(firstNameTxt);
- firstNameTxt.setFocus();
- }
- }
-}
--- /dev/null
+package org.argeo.app.ui.people;
+
+import static org.argeo.eclipse.ui.EclipseUiUtils.isEmpty;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+import org.argeo.api.acr.Content;
+import org.argeo.app.core.SuiteUtils;
+import org.argeo.app.ui.SuiteMsg;
+import org.argeo.app.ui.SuiteUiUtils;
+import org.argeo.cms.CmsUserManager;
+import org.argeo.cms.acr.ContentUtils;
+import org.argeo.cms.swt.dialogs.CmsFeedback;
+import org.argeo.cms.swt.widgets.SwtGuidedFormPage;
+import org.argeo.cms.ux.widgets.AbstractGuidedForm;
+import org.argeo.eclipse.ui.EclipseUiUtils;
+import org.argeo.util.directory.HierarchyUnit;
+import org.argeo.util.naming.LdapAttrs;
+import org.argeo.util.naming.LdapObjs;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Text;
+import org.osgi.service.useradmin.User;
+
+/** Ask first & last name. Update the passed node on finish */
+public class NewUserForm extends AbstractGuidedForm {
+ private Content hierarchyUnit;
+ private CmsUserManager cmsUserManager;
+
+ protected Text lastNameT;
+ protected Text firstNameT;
+ protected Text emailT;
+
+ public NewUserForm(CmsUserManager cmsUserManager, Content hierarchyUnit) {
+ this.hierarchyUnit = hierarchyUnit;
+ if (!hierarchyUnit.hasContentClass(LdapObjs.posixGroup.qName()))
+ throw new IllegalArgumentException(hierarchyUnit + " is not a POSIX group");
+ this.cmsUserManager = cmsUserManager;
+ }
+
+ @Override
+ public void addPages() {
+ try {
+ MainInfoPage page = new MainInfoPage("Main page");
+ addPage(page);
+ } catch (Exception e) {
+ throw new RuntimeException("Cannot add page to wizard", e);
+ }
+ setFormTitle(SuiteMsg.personWizardWindowTitle.lead());
+ }
+
+ /**
+ * Called when the user click on 'Finish' in the wizard. The task is then
+ * created and the corresponding session saved.
+ */
+ @Override
+ public boolean performFinish() {
+ String lastName = lastNameT.getText();
+ String firstName = firstNameT.getText();
+ String email = emailT.getText();
+ if (EclipseUiUtils.isEmpty(lastName) || EclipseUiUtils.isEmpty(firstName) || EclipseUiUtils.isEmpty(email)) {
+ CmsFeedback.show(SuiteMsg.allFieldsMustBeSet.lead());
+ return false;
+ } else {
+ UUID uuid = UUID.randomUUID();
+ String shortId = uuid.toString().split("-")[0];
+ String uid = "u" + shortId;
+ HierarchyUnit hu = hierarchyUnit.adapt(HierarchyUnit.class);
+ String username = "uid=" + uid + ",ou=People," + hu.getBase();
+
+ Map<String, Object> properties = new HashMap<>();
+ properties.put(LdapAttrs.givenName.name(), firstName);
+ properties.put(LdapAttrs.sn.name(), lastName);
+ properties.put(LdapAttrs.mail.name(), email);
+ properties.put(LdapAttrs.cn.name(), firstName + " " + lastName);
+ properties.put(LdapAttrs.employeeNumber.name(), uuid.toString());
+
+ Map<String, Object> credentials = new HashMap<>();
+ User user = cmsUserManager.createUser(username, properties, credentials);
+
+ Long huGidNumber = hierarchyUnit.get(LdapAttrs.gidNumber.qName(), Long.class).orElseThrow();
+ Long nextUserId = SuiteUtils.findNextId(hierarchyUnit, LdapObjs.posixAccount.qName());
+ String homeDirectory = "/home/" + uid;
+ Map<String, Object> additionalProperties = new HashMap<>();
+ additionalProperties.put(LdapAttrs.uidNumber.name(), nextUserId.toString());
+ additionalProperties.put(LdapAttrs.gidNumber.name(), huGidNumber.toString());
+ additionalProperties.put(LdapAttrs.homeDirectory.name(), homeDirectory);
+
+ Set<String> objectClasses = new HashSet<>();
+ objectClasses.add(LdapObjs.posixAccount.name());
+ cmsUserManager.addObjectClasses(user, objectClasses, additionalProperties);
+ return true;
+ }
+ }
+
+ @Override
+ public boolean performCancel() {
+ return true;
+ }
+
+ @Override
+ public boolean canFinish() {
+ String lastName = lastNameT.getText();
+ String firstName = firstNameT.getText();
+ String email = emailT.getText();
+ if (isEmpty(lastName) || isEmpty(firstName) || isEmpty(email)) {
+ return false;
+ } else
+ return true;
+ }
+
+ protected class MainInfoPage extends SwtGuidedFormPage {
+
+ public MainInfoPage(String pageName) {
+ super(pageName);
+ setTitle(SuiteMsg.personWizardPageTitle.lead());
+ }
+
+ public void createControl(Composite parent) {
+ parent.setLayout(new GridLayout(2, false));
+
+ // FirstName
+ SuiteUiUtils.createBoldLabel(parent, SuiteMsg.firstName);
+ firstNameT = new Text(parent, SWT.BORDER);
+ // firstNameTxt.setMessage("a first name");
+ firstNameT.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ // LastName
+ SuiteUiUtils.createBoldLabel(parent, SuiteMsg.lastName);
+ lastNameT = new Text(parent, SWT.BORDER);
+ // lastNameTxt.setMessage("a last name");
+ lastNameT.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ SuiteUiUtils.createBoldLabel(parent, SuiteMsg.email);
+ emailT = new Text(parent, SWT.BORDER);
+ emailT.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ ModifyListener ml = new ModifyListener() {
+ private static final long serialVersionUID = 1939491923843870844L;
+
+ @Override
+ public void modifyText(ModifyEvent event) {
+ getView().updateButtons();
+ }
+ };
+
+ firstNameT.addModifyListener(ml);
+ lastNameT.addModifyListener(ml);
+ emailT.addModifyListener(ml);
+
+ firstNameT.setFocus();
+ }
+ }
+}
import org.argeo.api.cms.ux.CmsView;
import org.argeo.app.ui.SuiteEvent;
import org.argeo.app.ui.SuiteIcon;
-import org.argeo.app.ui.dialogs.NewUserWizard;
import org.argeo.cms.CmsUserManager;
import org.argeo.cms.acr.ContentUtils;
import org.argeo.cms.auth.CmsRole;
import org.argeo.cms.auth.CurrentUser;
import org.argeo.cms.auth.UserAdminUtils;
import org.argeo.cms.jcr.acr.JcrContent;
-import org.argeo.cms.jface.dialog.CmsWizardDialog;
import org.argeo.cms.swt.CmsSwtTheme;
import org.argeo.cms.swt.CmsSwtUtils;
import org.argeo.cms.swt.Selected;
import org.argeo.util.naming.LdapAttrs;
import org.argeo.util.naming.LdapObjs;
import org.eclipse.jface.window.Window;
-import org.eclipse.jface.wizard.Wizard;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.layout.GridData;
});
addItem.addSelectionListener((Selected) (e) -> {
- // SuiteUtils.getOrCreateUserNode(adminSession, userDn);
- GuidedForm wizard = new NewUserWizard(null);
+ HierarchyUnit hierarchyUnit = usersPart.getInput();
+ Content huContent = ContentUtils.hierarchyUnitToContent(contentSession, hierarchyUnit);
+ GuidedForm wizard = new NewUserForm(cmsUserManager, huContent);
SwtGuidedFormDialog dialog = new SwtGuidedFormDialog(parent.getShell(), wizard);
// WizardDialog dialog = new WizardDialog(shell, wizard);
if (dialog.open() == Window.OK) {