From a3321ab7166dba6879444074d8cac5a11c992f76 Mon Sep 17 00:00:00 2001 From: srosse <none@none> Date: Thu, 15 Jan 2015 08:38:37 +0100 Subject: [PATCH] OO-1391: replace the search by userProperties map in User by an "exists" using a new and independent mapping of user property. --- .../basesecurity/BaseSecurityManager.java | 34 ++++-- .../olat/basesecurity/model/UserProperty.java | 111 ++++++++++++++++++ .../persistence/_spring/core_persistence.xml | 1 + .../GetIdentitiesByPowerSearchTest.java | 15 ++- 4 files changed, 143 insertions(+), 18 deletions(-) create mode 100644 src/main/java/org/olat/basesecurity/model/UserProperty.java diff --git a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java index 6c4615e9a96..c72653c6f3f 100644 --- a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java +++ b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java @@ -853,11 +853,11 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity { @Override public SecurityGroup findSecurityGroupByName(String securityGroupName) { StringBuilder sb = new StringBuilder(); - sb.append("select sgi from ").append(NamedGroupImpl.class.getName()).append(" as ngroup, ") - .append(SecurityGroupImpl.class.getName()).append(" as sgi ") - .append(" where ngroup.groupName=:groupName and ngroup.securityGroup=sgi"); + sb.append("select sgi from ").append(NamedGroupImpl.class.getName()).append(" as ngroup ") + .append(" inner join ngroup.securityGroup sgi") + .append(" where ngroup.groupName=:groupName"); - List<SecurityGroup> group = this.dbInstance.getCurrentEntityManager() + List<SecurityGroup> group = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), SecurityGroup.class) .setParameter("groupName", securityGroupName) .setHint("org.hibernate.cacheable", Boolean.TRUE) @@ -1392,7 +1392,7 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity { // In any case join with the user. Don't join-fetch user, this breaks the query // because of the user fields (don't know exactly why this behaves like // this) - sb.append(" join ident.user as user "); + sb.append(" inner join fetch ident.user as user "); if (hasGroups) { // join over security group memberships @@ -1461,23 +1461,27 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity { // handle email fields special: search in all email fields if (!emailProperties.isEmpty()) { - needsUserPropertiesJoin = checkIntersectionInUserProperties(sb,needsUserPropertiesJoin, params.isUserPropertiesAsIntersectionSearch()); + needsUserPropertiesJoin = checkIntersectionInUserProperties(sb, needsUserPropertiesJoin, params.isUserPropertiesAsIntersectionSearch()); boolean moreThanOne = emailProperties.size() > 1; if (moreThanOne) sb.append("("); boolean needsOr = false; for (String key : emailProperties.keySet()) { if (needsOr) sb.append(" or "); - //fxdiff + + sb.append(" exists (select prop").append(key).append(".value from userproperty prop").append(key).append(" where ") + .append(" prop").append(key).append(".propertyId.userId=user.key and prop").append(key).append(".propertyId.name ='").append(key).append("'") + .append(" and "); if(dbVendor.equals("mysql")) { - sb.append(" user.userProperties['").append(key).append("'] like :").append(key).append("_value "); + sb.append(" prop").append(key).append(".value like :").append(key).append("_value "); } else { - sb.append(" lower(user.userProperties['").append(key).append("']) like :").append(key).append("_value "); + sb.append(" lower(prop").append(key).append(".value) like :").append(key).append("_value "); } if(dbVendor.equals("oracle")) { sb.append(" escape '\\'"); } + sb.append(")"); needsOr = true; - } + } if (moreThanOne) sb.append(")"); // cleanup emailProperties.clear(); @@ -1485,15 +1489,19 @@ public class BaseSecurityManager extends BasicManager implements BaseSecurity { // add other fields for (String key : otherProperties.keySet()) { - needsUserPropertiesJoin = checkIntersectionInUserProperties(sb,needsUserPropertiesJoin, params.isUserPropertiesAsIntersectionSearch()); + needsUserPropertiesJoin = checkIntersectionInUserProperties(sb, needsUserPropertiesJoin, params.isUserPropertiesAsIntersectionSearch()); + sb.append(" exists (select prop").append(key).append(".value from userproperty prop").append(key).append(" where ") + .append(" prop").append(key).append(".propertyId.userId=user.key and prop").append(key).append(".propertyId.name ='").append(key).append("'") + .append(" and "); if(dbVendor.equals("mysql")) { - sb.append(" user.userProperties['").append(key).append("'] like :").append(key).append("_value "); + sb.append(" prop").append(key).append(".value like :").append(key).append("_value "); } else { - sb.append(" lower(user.userProperties['").append(key).append("']) like :").append(key).append("_value "); + sb.append(" lower(prop").append(key).append(".value) like :").append(key).append("_value "); } if(dbVendor.equals("oracle")) { sb.append(" escape '\\'"); } + sb.append(")"); needsAnd = true; } // cleanup diff --git a/src/main/java/org/olat/basesecurity/model/UserProperty.java b/src/main/java/org/olat/basesecurity/model/UserProperty.java new file mode 100644 index 00000000000..a7f622cf710 --- /dev/null +++ b/src/main/java/org/olat/basesecurity/model/UserProperty.java @@ -0,0 +1,111 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.basesecurity.model; + +import java.io.Serializable; + +import javax.persistence.Column; +import javax.persistence.Embeddable; +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.Table; + +/** + * + * This is only an helper mapping for the power search. Don't use it to persist + * or update user property. + * + * Initial date: 14.01.2015<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Table(name="o_userproperty") +@Entity(name="userproperty") +public class UserProperty { + + @EmbeddedId + private UserPropertyId propertyId; + + @Column(name="propvalue", nullable=false, insertable=false, updatable=false) + private String value; + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + + @Embeddable + public static class UserPropertyId implements Serializable { + + private static final long serialVersionUID = -1215870965613146741L; + + @Column(name = "fk_user_id") + private Long userId; + @Column(name = "propname") + private String name; + + public UserPropertyId() { + // + } + + public Long getUserId() { + return userId; + } + + + public void setUserId(Long userId) { + this.userId = userId; + } + + + public String getName() { + return name; + } + + + public void setName(String name) { + this.name = name; + } + + + @Override + public int hashCode() { + return (userId == null ? 478 : userId.hashCode()) + + (name == null ? 765912 : name.hashCode()); + } + + @Override + public boolean equals(Object obj) { + if(this == obj) { + return true; + } + if(obj instanceof UserPropertyId) { + UserPropertyId id = (UserPropertyId)obj; + return userId != null && userId.equals(id.userId) + && name != null && name.equals(id.name); + } + return false; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml b/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml index cf5e5776f78..65b2edbd6bd 100644 --- a/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml +++ b/src/main/java/org/olat/core/commons/persistence/_spring/core_persistence.xml @@ -92,6 +92,7 @@ <class>org.olat.basesecurity.model.GroupImpl</class> <class>org.olat.basesecurity.model.GrantImpl</class> <class>org.olat.basesecurity.model.GroupMembershipImpl</class> + <class>org.olat.basesecurity.model.UserProperty</class> <class>org.olat.core.dispatcher.mapper.model.PersistedMapper</class> <class>org.olat.core.commons.services.notifications.model.SubscriberImpl</class> <class>org.olat.core.commons.services.notifications.model.PublisherImpl</class> diff --git a/src/test/java/org/olat/basesecurity/GetIdentitiesByPowerSearchTest.java b/src/test/java/org/olat/basesecurity/GetIdentitiesByPowerSearchTest.java index 2bc3ea68c97..3049c953a32 100644 --- a/src/test/java/org/olat/basesecurity/GetIdentitiesByPowerSearchTest.java +++ b/src/test/java/org/olat/basesecurity/GetIdentitiesByPowerSearchTest.java @@ -39,6 +39,7 @@ import java.util.UUID; import junit.framework.Assert; import org.junit.Test; +import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.DBFactory; import org.olat.core.id.Identity; import org.olat.core.id.Roles; @@ -60,6 +61,8 @@ public class GetIdentitiesByPowerSearchTest extends OlatTestCase { private static final OLog log = Tracing.createLoggerFor(GetIdentitiesByPowerSearchTest.class); + @Autowired + private DB dbInstance; @Autowired private BaseSecurity baseSecurityManager; @@ -69,12 +72,12 @@ public class GetIdentitiesByPowerSearchTest extends OlatTestCase { Identity ident = JunitTestHelper.createAndPersistIdentityAsUser("anIdentity-" + suffix); Identity uniIdent = getOrCreateTestIdentity("extremegroovy-" + suffix); Assert.assertNotNull(uniIdent); - Identity deletedIdent = getOrCreateTestIdentity("delete"); + Identity deletedIdent = getOrCreateTestIdentity("delete-" + suffix); deletedIdent = baseSecurityManager.saveIdentityStatus(deletedIdent, Identity.STATUS_DELETED); SecurityGroup admins = baseSecurityManager.findSecurityGroupByName(Constants.GROUP_ADMIN); baseSecurityManager.addIdentityToSecurityGroup(deletedIdent, admins); - + dbInstance.commitAndCloseSession(); // basic query to find all system users without restrictions List<Identity> results = baseSecurityManager.getIdentitiesByPowerSearch(null, null, true, null, null, null, null, null, null, null, null); @@ -116,12 +119,12 @@ public class GetIdentitiesByPowerSearchTest extends OlatTestCase { Identity ident = JunitTestHelper.createAndPersistIdentityAsUser("anIdentity-" + suffix); Identity uniIdent = getOrCreateTestIdentity("extremegroovy-" + suffix); Assert.assertNotNull(uniIdent); - Identity deletedIdent = getOrCreateTestIdentity("delete"); + Identity deletedIdent = getOrCreateTestIdentity("delete-" + suffix); deletedIdent = baseSecurityManager.saveIdentityStatus(deletedIdent, Identity.STATUS_DELETED); SecurityGroup admins = baseSecurityManager.findSecurityGroupByName(Constants.GROUP_ADMIN); baseSecurityManager.addIdentityToSecurityGroup(deletedIdent, admins); - + dbInstance.commitAndCloseSession(); //search institutional name with *zh2 Map<String, String> userProperties = new HashMap<String, String>(); @@ -198,6 +201,8 @@ public class GetIdentitiesByPowerSearchTest extends OlatTestCase { Assert.assertFalse(results.contains(ident)); Assert.assertTrue(results.contains(uniIdent)); Assert.assertFalse(results.contains(deletedIdent)); + + dbInstance.commitAndCloseSession(); } @Test @@ -220,7 +225,7 @@ public class GetIdentitiesByPowerSearchTest extends OlatTestCase { baseSecurityManager.addIdentityToSecurityGroup(ident, authors); // security group search test - DBFactory.getInstance().closeSession(); + dbInstance.commitAndCloseSession(); SecurityGroup[] groups1 = {admins}; SecurityGroup[] groups2 = {admins, authors}; SecurityGroup[] groups3 = {authors}; -- GitLab