SLING-10192 Add option to set/edit properties on users and groups (#13)
diff --git a/src/main/java/org/apache/sling/jcr/repoinit/impl/NodePropertiesVisitor.java b/src/main/java/org/apache/sling/jcr/repoinit/impl/NodePropertiesVisitor.java
index d04c4c4..3483d69 100644
--- a/src/main/java/org/apache/sling/jcr/repoinit/impl/NodePropertiesVisitor.java
+++ b/src/main/java/org/apache/sling/jcr/repoinit/impl/NodePropertiesVisitor.java
@@ -16,24 +16,27 @@
*/
package org.apache.sling.jcr.repoinit.impl;
-import java.util.List;
+import java.util.ArrayList;
import java.util.Calendar;
+import java.util.List;
-import javax.jcr.Session;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
-import javax.jcr.Value;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.util.Text;
import org.apache.jackrabbit.value.BooleanValue;
import org.apache.jackrabbit.value.DateValue;
import org.apache.jackrabbit.value.DoubleValue;
import org.apache.jackrabbit.value.LongValue;
import org.apache.jackrabbit.value.StringValue;
-
import org.apache.sling.repoinit.parser.operations.PropertyLine;
import org.apache.sling.repoinit.parser.operations.SetProperties;
+import org.jetbrains.annotations.NotNull;
/**
* OperationVisitor which processes only operations related to setting node
@@ -41,6 +44,16 @@
* the execution order.
*/
class NodePropertiesVisitor extends DoNothingVisitor {
+ /**
+ * The repoinit.parser transforms the authorizable(ids)[/relative_path] path
+ * syntax from the original source into ":authorizable:ids#/relative_path" in the
+ * values provided from {@link SetProperties#getPaths()}
+ *
+ * These constants are used to unwind those values into the parts for processing
+ */
+ private static final String PATH_AUTHORIZABLE = ":authorizable:";
+ private static final char ID_DELIMINATOR = ',';
+ private static final char SUBTREE_DELIMINATOR = '#';
/**
* Create a visitor using the supplied JCR Session.
@@ -70,30 +83,135 @@
return(!n.hasProperty(name) || n.getProperty(name) == null);
}
+ /**
+ * True if the property needs to be set - if false, it is not touched. This
+ * handles the "default" repoinit instruction, which means "do not change the
+ * property if already set"
+ *
+ * @throws RepositoryException
+ * @throws PathNotFoundException
+ */
+ private static boolean needToSetProperty(Authorizable a, String pRelPath, boolean isDefault) throws RepositoryException {
+ if (!isDefault) {
+ // It's a "set" line -> overwrite existing value if any
+ return true;
+ }
+
+ // Otherwise set the property only if not set yet
+ return(!a.hasProperty(pRelPath) || a.getProperty(pRelPath) == null);
+ }
+
+ /**
+ * Build relative property path from a subtree path and a property name
+ * @param subTreePath the subtree path (may be null or empty)
+ * @param name the property name
+ * @return the relative path of the property
+ */
+ private static String toRelPath(String subTreePath, final String name) {
+ final String pRelPath;
+ if (subTreePath == null || subTreePath.isEmpty()) {
+ pRelPath = name;
+ } else {
+ if (subTreePath.startsWith("/")) {
+ subTreePath = subTreePath.substring(1);
+ }
+ pRelPath = String.format("%s/%s", subTreePath, name);
+ }
+ return pRelPath;
+ }
+
+ /**
+ * Lookup the authorizables for the given ids
+ * @param session the jcr session
+ * @param ids delimited list of authorizable ids
+ * @return iterator over the found authorizables
+ */
+ @NotNull
+ private static Iterable<Authorizable> getAuthorizables(@NotNull Session session, @NotNull String ids) throws RepositoryException {
+ List<Authorizable> authorizables = new ArrayList<>();
+ for (String id : Text.explode(ids, ID_DELIMINATOR)) {
+ Authorizable a = UserUtil.getAuthorizable(session, id);
+ if (a == null) {
+ throw new PathNotFoundException("Cannot resolve path of authorizable with id '" + id + "'.");
+ }
+ authorizables.add(a);
+ }
+ return authorizables;
+ }
+
+ /**
+ * Set properties on a user or group
+ *
+ * @param nodePath the target path
+ * @param propertyLines the property lines to process to set the properties
+ */
+ private void setAuthorizableProperties(String nodePath, List<PropertyLine> propertyLines) throws RepositoryException {
+ int lastHashIndex = nodePath.lastIndexOf(SUBTREE_DELIMINATOR);
+ if (lastHashIndex == -1) {
+ throw new IllegalStateException("Invalid format of authorizable path: # deliminator expected.");
+ }
+ String ids = nodePath.substring(PATH_AUTHORIZABLE.length(), lastHashIndex);
+ String subTreePath = nodePath.substring(lastHashIndex + 1);
+ for (Authorizable a : getAuthorizables(session, ids)) {
+ log.info("Setting properties on authorizable '{}'", a.getID());
+ for (PropertyLine pl : propertyLines) {
+ final String pName = pl.getPropertyName();
+ final String pRelPath = toRelPath(subTreePath, pName);
+ if (needToSetProperty(a, pRelPath, pl.isDefault())) {
+ final List<Object> values = pl.getPropertyValues();
+ if (values.size() > 1) {
+ Value[] pValues = convertToValues(values);
+ a.setProperty(pRelPath, pValues);
+ } else {
+ Value pValue = convertToValue(values.get(0));
+ a.setProperty(pRelPath, pValue);
+ }
+ } else {
+ log.info("Property '{}' already set on authorizable '{}', existing value will not be overwritten in 'default' mode",
+ pRelPath, a.getID());
+ }
+ }
+ }
+ }
+
+ /**
+ * Set properties on a JCR node
+ *
+ * @param nodePath the target path
+ * @param propertyLines the property lines to process to set the properties
+ */
+ private void setNodeProperties(String nodePath, List<PropertyLine> propertyLines) throws RepositoryException {
+ log.info("Setting properties on nodePath '{}'", nodePath);
+ Node n = session.getNode(nodePath);
+ for (PropertyLine pl : propertyLines) {
+ final String pName = pl.getPropertyName();
+ if (needToSetProperty(n, pl)) {
+ final PropertyLine.PropertyType pType = pl.getPropertyType();
+ final int type = PropertyType.valueFromName(pType.name());
+ final List<Object> values = pl.getPropertyValues();
+ if (values.size() > 1) {
+ Value[] pValues = convertToValues(values);
+ n.setProperty(pName, pValues, type);
+ } else {
+ Value pValue = convertToValue(values.get(0));
+ n.setProperty(pName, pValue, type);
+ }
+ } else {
+ log.info("Property '{}' already set on path '{}', existing value will not be overwritten in 'default' mode",
+ pName, nodePath);
+ }
+ }
+ }
+
@Override
public void visitSetProperties(SetProperties sp) {
for (String nodePath : sp.getPaths()) {
try {
- log.info("Setting properties on nodePath '{}'", nodePath);
- Node n = session.getNode(nodePath);
- for (PropertyLine pl : sp.getPropertyLines()) {
- final String pName = pl.getPropertyName();
- final PropertyLine.PropertyType pType = pl.getPropertyType();
- final List<Object> values = pl.getPropertyValues();
- final int type = PropertyType.valueFromName(pType.name());
- if (needToSetProperty(n, pl)) {
- if (values.size() > 1) {
- Value[] pValues = convertToValues(values);
- n.setProperty(pName, pValues, type);
- } else {
- Value pValue = convertToValue(values.get(0));
- n.setProperty(pName, pValue, type);
- }
- } else {
- log.info(
- "Property '{}' already set on path '{}', existing value will not be overwritten in 'default' mode",
- pName, nodePath);
- }
+ if (nodePath.startsWith(PATH_AUTHORIZABLE)) {
+ // special case for setting properties on authorizable
+ setAuthorizableProperties(nodePath, sp.getPropertyLines());
+ } else {
+ setNodeProperties(nodePath, sp.getPropertyLines());
}
} catch (RepositoryException e) {
report(e, "Unable to set properties on path [" + nodePath + "]:" + e);
diff --git a/src/test/java/org/apache/sling/jcr/repoinit/SetPropertiesTest.java b/src/test/java/org/apache/sling/jcr/repoinit/SetPropertiesTest.java
index 67a886a..2914b5b 100644
--- a/src/test/java/org/apache/sling/jcr/repoinit/SetPropertiesTest.java
+++ b/src/test/java/org/apache/sling/jcr/repoinit/SetPropertiesTest.java
@@ -128,4 +128,173 @@
U.assertSVPropertyExists(path3, "one", vf.createValue("oneB"));
U.assertSVPropertyExists(path3, "two", vf.createValue("twoA"));
}
+
+ @Test
+ public void setUserProperties() throws Exception {
+ String userid = "user" + UUID.randomUUID();
+
+ U.assertUser("before creating user", userid, false);
+ U.parseAndExecute("create user " + userid);
+ U.assertUser("after creating user", userid, true);
+
+ assertAuthorizableProperties(userid);
+ assertAuthorizablePropertiesAgain(userid);
+ }
+
+ @Test
+ public void setSubTreeUserProperties() throws Exception {
+ String userid = "user" + UUID.randomUUID();
+
+ U.assertUser("before creating user", userid, false);
+ U.parseAndExecute("create user " + userid);
+ U.assertUser("after creating user", userid, true);
+
+ assertAuthorizableSubTreeProperties(userid);
+ assertAuthorizableSubTreePropertiesAgain(userid);
+ }
+
+ @Test
+ public void setGroupProperties() throws Exception {
+ String groupid = "group" + UUID.randomUUID();
+
+ U.assertGroup("before creating group", groupid, false);
+ U.parseAndExecute("create group " + groupid);
+ U.assertGroup("after creating group", groupid, true);
+
+ assertAuthorizableProperties(groupid);
+ assertAuthorizablePropertiesAgain(groupid);
+ }
+
+ @Test
+ public void setSubTreeGroupProperties() throws Exception {
+ String groupid = "group" + UUID.randomUUID();
+
+ U.assertGroup("before creating group", groupid, false);
+ U.parseAndExecute("create group " + groupid);
+ U.assertGroup("after creating group", groupid, true);
+
+ assertAuthorizableSubTreeProperties(groupid);
+ assertAuthorizableSubTreePropertiesAgain(groupid);
+ }
+
+ /**
+ * Set properties on an authorizable and then verify that the values were set
+ */
+ protected void assertAuthorizableProperties(String id) throws RepositoryException, RepoInitParsingException {
+ final String setPropsA =
+ "set properties on authorizable(" +id + ")\n"
+ + "set one to oneA\n"
+ + "default two to twoA\n"
+ + "set nested/one to oneA\n"
+ + "default nested/two to twoA\n"
+ + "set three to threeA, \"threeB\", threeC\n"
+ + "default four to fourA, \"fourB\"\n"
+ + "set nested/three to threeA, \"threeB\", threeC\n"
+ + "default nested/four to fourA, \"fourB\"\n"
+ + "end";
+
+ U.parseAndExecute(setPropsA);
+
+ U.assertAuthorizableSVPropertyExists(id, "one", vf.createValue("oneA"));
+ U.assertAuthorizableSVPropertyExists(id, "nested/one", vf.createValue("oneA"));
+ U.assertAuthorizableSVPropertyExists(id, "two", vf.createValue("twoA"));
+ U.assertAuthorizableSVPropertyExists(id, "nested/two", vf.createValue("twoA"));
+ U.assertAuthorizableMVPropertyExists(id, "three", new Value[] {
+ vf.createValue("threeA"),
+ vf.createValue("threeB"),
+ vf.createValue("threeC")
+ });
+ U.assertAuthorizableMVPropertyExists(id, "nested/three", new Value[] {
+ vf.createValue("threeA"),
+ vf.createValue("threeB"),
+ vf.createValue("threeC")
+ });
+ U.assertAuthorizableMVPropertyExists(id, "four", new Value[] {
+ vf.createValue("fourA"),
+ vf.createValue("fourB")
+ });
+ U.assertAuthorizableMVPropertyExists(id, "nested/four", new Value[] {
+ vf.createValue("fourA"),
+ vf.createValue("fourB")
+ });
+ }
+
+ /**
+ * Change values for existing properties on an authorizable and then verify that the values were set
+ * or not as appropriate
+ */
+ protected void assertAuthorizablePropertiesAgain(String id) throws RepositoryException, RepoInitParsingException {
+ final String setPropsA =
+ "set properties on authorizable(" + id + ")\n"
+ + "set one to changed_oneA\n"
+ + "default two to changed_twoA\n"
+ + "set nested/one to changed_oneA\n"
+ + "default nested/two to changed_twoA\n"
+ + "set three to changed_threeA, \"changed_threeB\", changed_threeC\n"
+ + "default four to changed_fourA, \"changed_fourB\"\n"
+ + "set nested/three to changed_threeA, \"changed_threeB\", changed_threeC\n"
+ + "default nested/four to changed_fourA, \"changed_fourB\"\n"
+ + "end";
+
+ U.parseAndExecute(setPropsA);
+
+ U.assertAuthorizableSVPropertyExists(id, "one", vf.createValue("changed_oneA"));
+ U.assertAuthorizableSVPropertyExists(id, "nested/one", vf.createValue("changed_oneA"));
+ U.assertAuthorizableSVPropertyExists(id, "two", vf.createValue("twoA"));
+ U.assertAuthorizableSVPropertyExists(id, "nested/two", vf.createValue("twoA"));
+ U.assertAuthorizableMVPropertyExists(id, "three", new Value[] {
+ vf.createValue("changed_threeA"),
+ vf.createValue("changed_threeB"),
+ vf.createValue("changed_threeC")
+ });
+ U.assertAuthorizableMVPropertyExists(id, "nested/three", new Value[] {
+ vf.createValue("changed_threeA"),
+ vf.createValue("changed_threeB"),
+ vf.createValue("changed_threeC")
+ });
+ U.assertAuthorizableMVPropertyExists(id, "four", new Value[] {
+ vf.createValue("fourA"),
+ vf.createValue("fourB")
+ });
+ U.assertAuthorizableMVPropertyExists(id, "nested/four", new Value[] {
+ vf.createValue("fourA"),
+ vf.createValue("fourB")
+ });
+ }
+
+ /**
+ * Set properties on a subtree of an authorizable and then verify that the values were set
+ */
+ protected void assertAuthorizableSubTreeProperties(String id)
+ throws RepositoryException, RepoInitParsingException {
+ final String setPropsA =
+ "set properties on authorizable(" + id + ")/nested\n"
+ + "set one to oneA\n"
+ + "default two to twoA\n"
+ + "end";
+
+ U.parseAndExecute(setPropsA);
+
+ U.assertAuthorizableSVPropertyExists(id, "nested/one", vf.createValue("oneA"));
+ U.assertAuthorizableSVPropertyExists(id, "nested/two", vf.createValue("twoA"));
+ }
+
+ /**
+ * Change values for existing properties on a subtree of an authorizable and then verify
+ * that the values were set or not as appropriate
+ */
+ protected void assertAuthorizableSubTreePropertiesAgain(String id)
+ throws RepositoryException, RepoInitParsingException {
+ final String setPropsA =
+ "set properties on authorizable(" + id + ")/nested\n"
+ + "set one to changed_oneA\n"
+ + "default two to changed_twoA\n"
+ + "end";
+
+ U.parseAndExecute(setPropsA);
+
+ U.assertAuthorizableSVPropertyExists(id, "nested/one", vf.createValue("changed_oneA"));
+ U.assertAuthorizableSVPropertyExists(id, "nested/two", vf.createValue("twoA"));
+ }
+
}
diff --git a/src/test/java/org/apache/sling/jcr/repoinit/impl/TestUtil.java b/src/test/java/org/apache/sling/jcr/repoinit/impl/TestUtil.java
index fb7e201..306c877 100644
--- a/src/test/java/org/apache/sling/jcr/repoinit/impl/TestUtil.java
+++ b/src/test/java/org/apache/sling/jcr/repoinit/impl/TestUtil.java
@@ -197,6 +197,32 @@
assertEquals(message + " to be member of " + groupId, expectToBeMember, isMember);
}
+ public void assertAuthorizableSVPropertyExists(String id, String propertyName, Value expectedValue) throws RepositoryException {
+ final Authorizable a = UserUtil.getAuthorizable(adminSession, id);
+ assertNotNull("failed to get authorizable for " + id, a);
+ if (!a.hasProperty(propertyName)) {
+ fail("No " + propertyName + " property for " + a.getID());
+ } else {
+ Value[] property = a.getProperty(propertyName);
+ assertNotNull("Expected non-null value for property: " + propertyName, property);
+ assertEquals("Expected one value for property: " + propertyName, 1, property.length);
+ Value actualValue = property[0];
+ assertEquals("Value mismatch for property: " + propertyName, expectedValue, actualValue);
+ }
+ }
+
+ public void assertAuthorizableMVPropertyExists(String id, String propertyName, Value[] expectedValues) throws RepositoryException {
+ final Authorizable a = UserUtil.getAuthorizable(adminSession, id);
+ assertNotNull("failed to get authorizable for " + id, a);
+ if (!a.hasProperty(propertyName)) {
+ fail("No " + propertyName + " property for " + a.getID());
+ } else {
+ Value[] actualValues = a.getProperty(propertyName);
+ assertNotNull("Expected non-null value for property: " + propertyName, actualValues);
+ assertArrayEquals("Values mismatch for property: " + propertyName, expectedValues, actualValues);
+ }
+ }
+
public void assertSVPropertyExists(String path, String propertyName, Value expectedValue) throws RepositoryException {
final Node n = adminSession.getNode(path);
if(!n.hasProperty(propertyName)) {
diff --git a/src/test/java/org/apache/sling/jcr/repoinit/it/RepoInitTextIT.java b/src/test/java/org/apache/sling/jcr/repoinit/it/RepoInitTextIT.java
index 11e2e2b..3bebc3c 100644
--- a/src/test/java/org/apache/sling/jcr/repoinit/it/RepoInitTextIT.java
+++ b/src/test/java/org/apache/sling/jcr/repoinit/it/RepoInitTextIT.java
@@ -24,11 +24,14 @@
import java.io.InputStreamReader;
import java.util.UUID;
-import javax.jcr.PropertyType;
-import javax.jcr.ValueFactory;
-import javax.jcr.Value;
import javax.inject.Inject;
+import javax.jcr.PropertyType;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.UserManager;
import org.apache.sling.jcr.repoinit.JcrRepoInitOpsProcessor;
import org.apache.sling.repoinit.parser.RepoInitParser;
import org.junit.Before;
@@ -211,4 +214,126 @@
}
};
}
+
+ @Test
+ public void setAuthorizableProperties() throws Exception {
+ new Retry() {
+ @Override
+ public Void call() throws Exception {
+ if(!(session instanceof JackrabbitSession)) {
+ throw new IllegalArgumentException("Session is not a JackrabbitSession");
+ }
+ UserManager um = ((JackrabbitSession)session).getUserManager();
+
+ Authorizable [] authorizables = new Authorizable[] {
+ um.getAuthorizable(ALICE),
+ um.getAuthorizable(GROUP_A)
+ };
+
+ for (Authorizable authorizable : authorizables) {
+ assertNotNull("Expected authorizable to not be null", authorizable);
+ ValueFactory vf = session.getValueFactory();
+ Value[] expectedValues1 = new Value[2];
+ expectedValues1[0] = vf.createValue("/d/e/f/*");
+ expectedValues1[1] = vf.createValue("m/n/*");
+ assertTrue("Expecting array type property " + PROP_A + " to be present ", U.hasProperty(authorizable, PROP_A, expectedValues1));
+
+ Value expectedValue2 = vf.createValue("42", PropertyType.valueFromName("Long"));
+ assertTrue("Expecting Long type default property " + PROP_B + " to be present ", U.hasProperty(authorizable, PROP_B, expectedValue2));
+
+ Value expectedValue3 = vf.createValue("true", PropertyType.valueFromName("Boolean"));
+ assertTrue("Expecting bool type property " + PROP_C + " to be present ", U.hasProperty(authorizable, PROP_C, expectedValue3));
+
+ Value expectedValue4 = vf.createValue("2020-03-19T11:39:33.437+05:30", PropertyType.valueFromName("Date"));
+ assertTrue("Expecting date type property " + PROP_D + " to be present " , U.hasProperty(authorizable, PROP_D, expectedValue4));
+
+ Value expectedValue5 = vf.createValue("test");
+ assertTrue("Expecting string type property " + PROP_E + " to be present " , U.hasProperty(authorizable, PROP_E, expectedValue5));
+
+ Value expectedValue6 = vf.createValue("hello, you!");
+ assertTrue("Expecting quoted string type property " + PROP_F + " to be present " , U.hasProperty(authorizable, PROP_F, expectedValue6));
+
+ Value[] expectedValues7 = new Value[2];
+ expectedValues7[0] = vf.createValue("test1");
+ expectedValues7[1] = vf.createValue("test2");
+ assertTrue("Expecting string array type property " + PROP_G + " to be present " , U.hasProperty(authorizable, PROP_G, expectedValues7));
+
+ Value expectedValue8 = vf.createValue("Here's a \"double quoted string\" with suffix");
+ assertTrue("Expecting quoted string type property " + PROP_H + " to be present " , U.hasProperty(authorizable, PROP_H, expectedValue8));
+
+ Value[] expectedValues9 = new Value[3];
+ expectedValues9[0] = vf.createValue("quoted");
+ expectedValues9[1] = vf.createValue("non-quoted");
+ expectedValues9[2] = vf.createValue("the last \" one");
+ assertTrue("Expecting string array type property " + PROP_I + " to be present " , U.hasProperty(authorizable, PROP_I, expectedValues9));
+
+ Value nestedExpectedValue = vf.createValue("42", PropertyType.valueFromName("Long"));
+ assertTrue("Expecting Long type default property nested/" + PROP_B + " to be present ", U.hasProperty(authorizable, "nested/" +PROP_B, nestedExpectedValue));
+ }
+
+ return null;
+ }
+ };
+ }
+
+ @Test
+ public void setAuthorizableSubTreeProperties() throws Exception {
+ new Retry() {
+ @Override
+ public Void call() throws Exception {
+ if(!(session instanceof JackrabbitSession)) {
+ throw new IllegalArgumentException("Session is not a JackrabbitSession");
+ }
+ UserManager um = ((JackrabbitSession)session).getUserManager();
+
+ Authorizable [] authorizables = new Authorizable[] {
+ um.getAuthorizable(BOB),
+ um.getAuthorizable(GROUP_B)
+ };
+
+ for (Authorizable authorizable : authorizables) {
+ assertNotNull("Expected authorizable to not be null", authorizable);
+ ValueFactory vf = session.getValueFactory();
+ Value[] expectedValues1 = new Value[2];
+ expectedValues1[0] = vf.createValue("/d/e/f/*");
+ expectedValues1[1] = vf.createValue("m/n/*");
+ assertTrue("Expecting array type property nested/" + PROP_A + " to be present ", U.hasProperty(authorizable, "nested/" + PROP_A, expectedValues1));
+
+ Value expectedValue2 = vf.createValue("42", PropertyType.valueFromName("Long"));
+ assertTrue("Expecting Long type default property nested/" + PROP_B + " to be present ", U.hasProperty(authorizable, "nested/" + PROP_B, expectedValue2));
+
+ Value expectedValue3 = vf.createValue("true", PropertyType.valueFromName("Boolean"));
+ assertTrue("Expecting bool type property nested/" + PROP_C + " to be present ", U.hasProperty(authorizable, "nested/" + PROP_C, expectedValue3));
+
+ Value expectedValue4 = vf.createValue("2020-03-19T11:39:33.437+05:30", PropertyType.valueFromName("Date"));
+ assertTrue("Expecting date type property nested/" + PROP_D + " to be present " , U.hasProperty(authorizable, "nested/" + PROP_D, expectedValue4));
+
+ Value expectedValue5 = vf.createValue("test");
+ assertTrue("Expecting string type property nested/" + PROP_E + " to be present " , U.hasProperty(authorizable, "nested/" + PROP_E, expectedValue5));
+
+ Value expectedValue6 = vf.createValue("hello, you!");
+ assertTrue("Expecting quoted string type property nested/" + PROP_F + " to be present " , U.hasProperty(authorizable, "nested/" + PROP_F, expectedValue6));
+
+ Value[] expectedValues7 = new Value[2];
+ expectedValues7[0] = vf.createValue("test1");
+ expectedValues7[1] = vf.createValue("test2");
+ assertTrue("Expecting string array type property nested/" + PROP_G + " to be present " , U.hasProperty(authorizable, "nested/" + PROP_G, expectedValues7));
+
+ Value expectedValue8 = vf.createValue("Here's a \"double quoted string\" with suffix");
+ assertTrue("Expecting quoted string type property nested/" + PROP_H + " to be present " , U.hasProperty(authorizable, "nested/" + PROP_H, expectedValue8));
+
+ Value[] expectedValues9 = new Value[3];
+ expectedValues9[0] = vf.createValue("quoted");
+ expectedValues9[1] = vf.createValue("non-quoted");
+ expectedValues9[2] = vf.createValue("the last \" one");
+ assertTrue("Expecting string array type property nested/" + PROP_I + " to be present " , U.hasProperty(authorizable, "nested/" + PROP_I, expectedValues9));
+
+ Value nestedExpectedValue = vf.createValue("42", PropertyType.valueFromName("Long"));
+ assertTrue("Expecting Long type default property nested/nested/" + PROP_B + " to be present ", U.hasProperty(authorizable, "nested/nested/" +PROP_B, nestedExpectedValue));
+ }
+
+ return null;
+ }
+ };
+ }
}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/jcr/repoinit/it/U.java b/src/test/java/org/apache/sling/jcr/repoinit/it/U.java
index 1a404ff..381d2a9 100644
--- a/src/test/java/org/apache/sling/jcr/repoinit/it/U.java
+++ b/src/test/java/org/apache/sling/jcr/repoinit/it/U.java
@@ -135,4 +135,29 @@
}
return false;
}
+
+ public static boolean hasProperty(Authorizable a, String propertyName, Value propertyValue) throws RepositoryException {
+ if (a != null) {
+ boolean isPropertyPresent = a.hasProperty(propertyName);
+ if (isPropertyPresent) {
+ Value[] values = a.getProperty(propertyName);
+ if (values != null && values.length == 1) {
+ Value v = values[0];
+ return v.equals(propertyValue);
+ }
+ }
+ }
+ return false;
+ }
+
+ public static boolean hasProperty(Authorizable a, String propertyName, Value[] propertyValues) throws RepositoryException {
+ if (a != null) {
+ boolean isPropertyPresent = a.hasProperty(propertyName);
+ if (isPropertyPresent) {
+ Value[] v = a.getProperty(propertyName);
+ return Arrays.equals(v, propertyValues);
+ }
+ }
+ return false;
+ }
}
\ No newline at end of file
diff --git a/src/test/resources/repoinit.txt b/src/test/resources/repoinit.txt
index d6fd943..2dbbe24 100644
--- a/src/test/resources/repoinit.txt
+++ b/src/test/resources/repoinit.txt
@@ -81,4 +81,34 @@
default someInteger{Long} to 65
set quotedA to "Here's a \"double quoted string\" with suffix"
set quotedMix to "quoted", non-quoted, "the last \" one"
-end
\ No newline at end of file
+end
+
+# SLING-10192 set properties on user or group profile
+set properties on authorizable(alice),authorizable(grpA)
+ set pathArray to /d/e/f/*, m/n/*
+ default someInteger{Long} to 42
+ set someFlag{Boolean} to true
+ default someDate{Date} to "2020-03-19T11:39:33.437+05:30"
+ set customSingleValueStringProp to test
+ set customSingleValueQuotedStringProp to "hello, you!"
+ set stringArray to test1, test2
+ default someInteger{Long} to 65
+ set quotedA to "Here's a \"double quoted string\" with suffix"
+ set quotedMix to "quoted", non-quoted, "the last \" one"
+ set nested/someInteger{Long} to 42
+end
+
+# SLING-10192 set properties on a subtree of the user or group profile
+set properties on authorizable(bob)/nested,authorizable(grpB)/nested
+ set pathArray to /d/e/f/*, m/n/*
+ default someInteger{Long} to 42
+ set someFlag{Boolean} to true
+ default someDate{Date} to "2020-03-19T11:39:33.437+05:30"
+ set customSingleValueStringProp to test
+ set customSingleValueQuotedStringProp to "hello, you!"
+ set stringArray to test1, test2
+ default someInteger{Long} to 65
+ set quotedA to "Here's a \"double quoted string\" with suffix"
+ set quotedMix to "quoted", non-quoted, "the last \" one"
+ set nested/someInteger{Long} to 42
+end