Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.apache.syncope.core.persistence.api.entity.PlainAttrValue;
import org.apache.syncope.core.persistence.api.entity.PlainSchema;
import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
import org.springframework.data.domain.Sort;

public class MariaDBJPAAnySearchDAO extends AbstractJPAAnySearchDAO {

Expand Down Expand Up @@ -68,6 +69,35 @@ public MariaDBJPAAnySearchDAO(
entityManager);
}

@Override
protected void parseOrderByForPlainSchema(
final SearchSupport svs,
final OrderBySupport obs,
final OrderBySupport.Item item,
final Sort.Order clause,
final PlainSchema schema,
final String fieldName) {

// keep track of involvement of non-mandatory schemas in the order by clauses
obs.nonMandatorySchemas = !"true".equals(schema.getMandatoryCondition());

obs.views.add(svs.field());

item.select = new StringBuilder().
append("( SELECT usa").append('.').append(key(schema.getType())).
append(" FROM ").append(schema.isUniqueConstraint()
? svs.asSearchViewSupport().uniqueAttr().name()
: svs.asSearchViewSupport().attr().name()).
append(" usa WHERE usa.any_id = ").
append(defaultSV(svs).alias()).
append(".any_id").
append(" AND usa.schema_id ='").append(fieldName).append("'").
append(" LIMIT 1").
append(") AS ").append(fieldName).toString();
item.where = "plainSchema = '" + fieldName + '\'';
item.orderBy = fieldName + ' ' + clause.getDirection().name();
}

@Override
protected Pair<Boolean, AnySearchNode> getQuery(
final AttrCond cond,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,17 @@ protected void parseOrderByForPlainSchema(

obs.views.add(svs.field());

item.select = svs.field().alias() + '.'
+ (schema.isUniqueConstraint() ? "attrUniqueValue" : key(schema.getType()))
+ " AS " + fieldName;
item.select = new StringBuilder().append(schema.isUniqueConstraint()
? "( SELECT JSON_UNQUOTE(JSON_EXTRACT(usa.attrUniqueValue, '$. " + key(schema.getType()) + "')) "
: "( SELECT usa." + key(schema.getType())).
append(" FROM ").
append(svs.field().name()).
append(" usa WHERE usa.any_id = ").
append(svs.field().alias()).
append(".any_id").
append(" AND usa.plainSchema ='").append(fieldName).append("'").
append(" LIMIT 1").
append(") AS ").append(fieldName).toString();
item.where = "plainSchema = '" + fieldName + '\'';
item.orderBy = fieldName + ' ' + clause.getDirection().name();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@
import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.types.AnyTypeKind;
import org.apache.syncope.common.lib.types.IdRepoEntitlement;
import org.apache.syncope.core.persistence.api.attrvalue.PlainAttrValidationManager;
import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
import org.apache.syncope.core.persistence.api.dao.AnySearchDAO;
import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
import org.apache.syncope.core.persistence.api.dao.GroupDAO;
import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
import org.apache.syncope.core.persistence.api.dao.RealmDAO;
import org.apache.syncope.core.persistence.api.dao.RealmSearchDAO;
import org.apache.syncope.core.persistence.api.dao.RoleDAO;
Expand All @@ -56,6 +58,7 @@
import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
import org.apache.syncope.core.persistence.api.entity.AnyType;
import org.apache.syncope.core.persistence.api.entity.PlainAttr;
import org.apache.syncope.core.persistence.api.entity.PlainSchema;
import org.apache.syncope.core.persistence.api.entity.anyobject.AMembership;
import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
import org.apache.syncope.core.persistence.api.entity.group.Group;
Expand Down Expand Up @@ -105,6 +108,12 @@ public class AnySearchTest extends AbstractTest {
@Autowired
private RoleDAO roleDAO;

@Autowired
private PlainSchemaDAO plainSchemaDAO;

@Autowired
private PlainAttrValidationManager validator;

@BeforeEach
public void adjustLoginDateForLocalSystem() throws ParseException {
User rossini = userDAO.findByUsername("rossini").orElseThrow();
Expand Down Expand Up @@ -948,4 +957,85 @@ public void issueSYNCOPE1419() {
assertNotNull(users);
assertEquals(4, users.size());
}

@Test
public void issueSYNCOPE1906() {
User bellini = userDAO.findByUsername("bellini").orElseThrow();

PlainSchema ctypeSchema = plainSchemaDAO.findById("ctype").orElseThrow();
assertNotNull(ctypeSchema);

userDAO.save(addPlainAttr(bellini, ctypeSchema, "aa1"));

User puccini = userDAO.findByUsername("puccini").orElseThrow();
assertNotNull(bellini);

userDAO.save(addPlainAttr(puccini, ctypeSchema, "aa2"));

User verdi = userDAO.findByUsername("verdi").orElseThrow();
assertNotNull(verdi);

userDAO.save(addPlainAttr(verdi, ctypeSchema, "aa3"));

User vivaldi = userDAO.findByUsername("vivaldi").orElseThrow();
assertNotNull(vivaldi);

userDAO.save(addPlainAttr(vivaldi, ctypeSchema, "aa4"));

User rossini = userDAO.findByUsername("rossini").orElseThrow();
assertNotNull(rossini);

userDAO.save(addPlainAttr(rossini, ctypeSchema, "aa5"));

entityManager.flush();

AnyCond idCond = new AnyCond(AttrCond.Type.ISNOTNULL);
idCond.setSchema("id");

List<User> users =
searchDAO.search(SearchCond.of(idCond), List.of(new Sort.Order(Sort.Direction.DESC, "ctype")),
AnyTypeKind.USER);

assertEquals("bellini", users.get(4).getUsername());
assertEquals("puccini", users.get(3).getUsername());
assertEquals("verdi", users.get(2).getUsername());
assertEquals("vivaldi", users.get(1).getUsername());
assertEquals("rossini", users.get(0).getUsername());

// order by ctype even not searching by it
AttrCond surnameCond = new AttrCond(AttrCond.Type.ILIKE);
surnameCond.setSchema("surname");
surnameCond.setExpression("%ini");

AttrCond coolCond = new AttrCond(AttrCond.Type.ISNULL);
coolCond.setSchema("cool");

users = searchDAO.search(SearchCond.and(SearchCond.of(surnameCond), SearchCond.of(coolCond)),
List.of(new Sort.Order(Sort.Direction.DESC, "ctype")), AnyTypeKind.USER);

assertFalse(users.isEmpty());
assertEquals(2, users.size());

// order by unique attribute
users = searchDAO.search(SearchCond.of(idCond), List.of(new Sort.Order(Sort.Direction.DESC, "fullname")),
AnyTypeKind.USER);

assertEquals("vivaldi", users.get(4).getUsername());
assertEquals("puccini", users.get(3).getUsername());
assertEquals("rossini", users.get(2).getUsername());
assertEquals("verdi", users.get(1).getUsername());
assertEquals("bellini", users.get(0).getUsername());
}

private User addPlainAttr(final User user, final PlainSchema plainSchema, final String value) {
user.getPlainAttr(plainSchema.getKey())
.ifPresentOrElse(ctype -> ctype.getValues().get(0).setStringValue(value), () -> {
PlainAttr attr = new PlainAttr();
attr.setPlainSchema(plainSchema);
attr.add(validator, value);

user.add(attr);
});
return user;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
import org.apache.syncope.common.lib.types.TaskType;
import org.apache.syncope.common.lib.types.UnmatchingRule;
import org.apache.syncope.common.rest.api.RESTHeaders;
import org.apache.syncope.common.rest.api.beans.AnyQuery;
import org.apache.syncope.common.rest.api.beans.RealmQuery;
import org.apache.syncope.common.rest.api.beans.ReconQuery;
import org.apache.syncope.common.rest.api.beans.TaskQuery;
Expand Down Expand Up @@ -1895,4 +1896,105 @@ public void issueSYNCOPE1894() {
SCHEMA_SERVICE.delete(SchemaType.PLAIN, userWithDotSchema.getKey());
}
}

@Test
public void issueSYNCOPE1906() {
UserCR userCR = UserITCase.getUniqueSample("issuesyncope1906@syncope.apache.org");
userCR.getPlainAttrs()
.removeIf(attr -> "ctype".equals(attr.getSchema()) || "fullname".equals(attr.getSchema()));
userCR.getPlainAttrs().add(attr("ctype", "aa1"));
userCR.getPlainAttrs().add(attr("fullname", "aa1"));
UserTO aa1 = createUser(userCR).getEntity();

userCR = UserITCase.getUniqueSample("issuesyncope1906@syncope.apache.org");
userCR.getPlainAttrs()
.removeIf(attr -> "ctype".equals(attr.getSchema()) || "fullname".equals(attr.getSchema()));
userCR.getPlainAttrs().add(attr("ctype", "aa2"));
userCR.getPlainAttrs().add(attr("fullname", "aa2"));
UserTO aa2 = createUser(userCR).getEntity();

userCR = UserITCase.getUniqueSample("issuesyncope1906@syncope.apache.org");
userCR.getPlainAttrs()
.removeIf(attr -> "ctype".equals(attr.getSchema()) || "fullname".equals(attr.getSchema()));
userCR.getPlainAttrs().add(attr("ctype", "aa3"));
userCR.getPlainAttrs().add(attr("fullname", "aa3"));
UserTO aa3 = createUser(userCR).getEntity();

userCR = UserITCase.getUniqueSample("issuesyncope1906@syncope.apache.org");
userCR.getPlainAttrs()
.removeIf(attr -> "ctype".equals(attr.getSchema()) || "fullname".equals(attr.getSchema()));
userCR.getPlainAttrs().add(attr("ctype", "aa4"));
userCR.getPlainAttrs().add(attr("fullname", "aa4"));
UserTO aa4 = createUser(userCR).getEntity();

userCR = UserITCase.getUniqueSample("issuesyncope1906@syncope.apache.org");
userCR.getPlainAttrs()
.removeIf(attr -> "ctype".equals(attr.getSchema()) || "fullname".equals(attr.getSchema()));
userCR.getPlainAttrs().add(attr("ctype", "aa5"));
userCR.getPlainAttrs().add(attr("fullname", "aa5"));
UserTO aa5 = createUser(userCR).getEntity();

// add also other users with valued ctype
userCR = UserITCase.getUniqueSample("actype@syncope.apache.org");
userCR.getPlainAttrs()
.removeIf(attr -> "ctype".equals(attr.getSchema()) || "fullname".equals(attr.getSchema()));
userCR.getPlainAttrs().add(attr("ctype", "a ctype"));
userCR.getPlainAttrs().add(attr("fullname", "a fullname"));
createUser(userCR);

userCR = UserITCase.getUniqueSample("actypetwo@syncope.apache.org");
userCR.getPlainAttrs()
.removeIf(attr -> "ctype".equals(attr.getSchema()) || "fullname".equals(attr.getSchema()));
userCR.getPlainAttrs().add(attr("ctype", "a ctype 2"));
userCR.getPlainAttrs().add(attr("fullname", "a fullname 2"));
createUser(userCR);
try {
await().until(() -> USER_SERVICE.search(new AnyQuery.Builder().fiql(
SyncopeClient.getUserSearchConditionBuilder().is("email").equalTo("*issuesyncope1906*")
.query())
.size(0)
.page(1)
.build()).getTotalCount() == 5);
List<UserTO> users = USER_SERVICE.search(new AnyQuery.Builder().fiql(
SyncopeClient.getUserSearchConditionBuilder().is("email").equalTo("*issuesyncope1906*")
.query()).size(10).page(1).orderBy("ctype DESC").build()).getResult();

assertEquals(5, users.size());

assertEquals(aa1.getUsername(), users.get(4).getUsername());
assertEquals(aa2.getUsername(), users.get(3).getUsername());
assertEquals(aa3.getUsername(), users.get(2).getUsername());
assertEquals(aa4.getUsername(), users.get(1).getUsername());
assertEquals(aa5.getUsername(), users.get(0).getUsername());

users = USER_SERVICE.search(new AnyQuery.Builder().fiql(
SyncopeClient.getUserSearchConditionBuilder().is("email").equalTo("*issuesyncope1906*")
.query()).size(10).page(1).orderBy("ctype ASC").build()).getResult();

assertEquals(aa5.getUsername(), users.get(4).getUsername());
assertEquals(aa4.getUsername(), users.get(3).getUsername());
assertEquals(aa3.getUsername(), users.get(2).getUsername());
assertEquals(aa2.getUsername(), users.get(1).getUsername());
assertEquals(aa1.getUsername(), users.get(0).getUsername());

// order by unique attribute
users = USER_SERVICE.search(new AnyQuery.Builder().fiql(
SyncopeClient.getUserSearchConditionBuilder().is("email").equalTo("*issuesyncope1906*")
.query()).size(10).page(1).orderBy("fullname ASC").build()).getResult();

assertEquals(aa5.getUsername(), users.get(4).getUsername());
assertEquals(aa4.getUsername(), users.get(3).getUsername());
assertEquals(aa3.getUsername(), users.get(2).getUsername());
assertEquals(aa2.getUsername(), users.get(1).getUsername());
assertEquals(aa1.getUsername(), users.get(0).getUsername());

} finally {
USER_SERVICE.search(new AnyQuery.Builder().fiql(
SyncopeClient.getUserSearchConditionBuilder().is("ctype").equalTo("aa*").query())
.size(10)
.page(1)
.orderBy("ctype DESC")
.build()).getResult().forEach(u -> deleteUser(u.getKey()));
}
}
}
Loading