mirror of
https://gitee.com/jmix/cuba.git
synced 2024-12-05 04:38:10 +08:00
PL-10102 EntityLog doesn't show changes for dynamic attributes
This commit is contained in:
parent
aba7b72a3d
commit
fea4a162f6
@ -16,16 +16,16 @@
|
||||
*/
|
||||
package com.haulmont.cuba.security.app;
|
||||
|
||||
import com.haulmont.bali.util.Preconditions;
|
||||
import com.haulmont.chile.core.datatypes.Datatypes;
|
||||
import com.haulmont.chile.core.model.Instance;
|
||||
import com.haulmont.chile.core.model.MetaClass;
|
||||
import com.haulmont.chile.core.model.MetaProperty;
|
||||
import com.haulmont.chile.core.model.Range;
|
||||
import com.haulmont.cuba.core.EntityManager;
|
||||
import com.haulmont.cuba.core.Persistence;
|
||||
import com.haulmont.cuba.core.Transaction;
|
||||
import com.haulmont.cuba.core.TypedQuery;
|
||||
import com.haulmont.cuba.core.*;
|
||||
import com.haulmont.cuba.core.app.ServerConfig;
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributes;
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesUtils;
|
||||
import com.haulmont.cuba.core.entity.*;
|
||||
import com.haulmont.cuba.core.global.*;
|
||||
import com.haulmont.cuba.core.sys.AppContext;
|
||||
@ -64,6 +64,10 @@ public class EntityLog implements EntityLogAPI {
|
||||
@Inject
|
||||
protected ReferenceToEntitySupport referenceToEntitySupport;
|
||||
@Inject
|
||||
protected DynamicAttributes dynamicAttributes;
|
||||
@Inject
|
||||
protected DataManager dataManager;
|
||||
@Inject
|
||||
protected ServerConfig serverConfig;
|
||||
|
||||
protected volatile boolean loaded;
|
||||
@ -145,6 +149,12 @@ public class EntityLog implements EntityLogAPI {
|
||||
}
|
||||
}
|
||||
|
||||
if (itemToSave.getType() == EntityLogItem.Type.MODIFY) {
|
||||
sameEntityList.stream()
|
||||
.filter(entityLogItem -> entityLogItem.getType() == EntityLogItem.Type.CREATE)
|
||||
.findFirst()
|
||||
.ifPresent(entityLogItem -> itemToSave.setType(EntityLogItem.Type.CREATE));
|
||||
}
|
||||
itemToSave.setChanges(getChanges(properties));
|
||||
}
|
||||
|
||||
@ -167,6 +177,7 @@ public class EntityLog implements EntityLogAPI {
|
||||
.orElse(null);
|
||||
if (attr == null) {
|
||||
attr = metadata.create(EntityLogAttr.class);
|
||||
attr.setName(entityLogAttr.getName());
|
||||
itemToSave.getAttributes().add(attr);
|
||||
}
|
||||
return attr;
|
||||
@ -279,9 +290,15 @@ public class EntityLog implements EntityLogAPI {
|
||||
}
|
||||
|
||||
protected String getEntityName(Entity entity) {
|
||||
MetaClass metaClass = metadata.getSession().getClassNN(entity.getClass());
|
||||
MetaClass originalMetaClass = metadata.getExtendedEntities().getOriginalMetaClass(metaClass);
|
||||
return originalMetaClass != null ? originalMetaClass.getName() : metaClass.getName();
|
||||
MetaClass metaClass;
|
||||
if (entity instanceof CategoryAttributeValue) {
|
||||
CategoryAttribute categoryAttribute = ((CategoryAttributeValue) entity).getCategoryAttribute();
|
||||
Preconditions.checkNotNullArgument(categoryAttribute,"Category attribute is null");
|
||||
metaClass = metadata.getClassNN(categoryAttribute.getCategoryEntityType());
|
||||
} else {
|
||||
metaClass = metadata.getSession().getClassNN(entity.getClass());
|
||||
}
|
||||
return metadata.getExtendedEntities().getOriginalOrThisMetaClass(metaClass).getName();
|
||||
}
|
||||
|
||||
protected boolean doNotRegister(Entity entity) {
|
||||
@ -309,9 +326,10 @@ public class EntityLog implements EntityLogAPI {
|
||||
try {
|
||||
if (doNotRegister(entity))
|
||||
return;
|
||||
String masterEntityName = getEntityName(entity);
|
||||
boolean isCategoryAttributeValue = entity instanceof CategoryAttributeValue;
|
||||
|
||||
String entityName = getEntityName(entity);
|
||||
Set<String> attributes = getLoggedAttributes(entityName, auto);
|
||||
Set<String> attributes = getLoggedAttributes(masterEntityName, auto);
|
||||
if (attributes != null && attributes.contains("*")) {
|
||||
attributes = getAllAttributes(entity);
|
||||
}
|
||||
@ -319,17 +337,21 @@ public class EntityLog implements EntityLogAPI {
|
||||
return;
|
||||
}
|
||||
|
||||
MetaClass metaClass = metadata.getClassNN(entityName);
|
||||
MetaClass metaClass = metadata.getClassNN(masterEntityName);
|
||||
attributes = filterRemovedAttributes(metaClass, attributes);
|
||||
|
||||
String storeName = metadata.getTools().getStoreName(metaClass);
|
||||
if (Stores.isMain(storeName)) {
|
||||
internalRegisterCreate(entity, entityName, attributes);
|
||||
if (isCategoryAttributeValue) {
|
||||
internalRegisterModifyAttributeValue((CategoryAttributeValue) entity, null, attributes);
|
||||
} else {
|
||||
// Create a new transaction in main DB if we are saving an entity from additional data store
|
||||
try (Transaction tx = persistence.createTransaction()) {
|
||||
internalRegisterCreate(entity, entityName, attributes);
|
||||
tx.commit();
|
||||
String storeName = metadata.getTools().getStoreName(metaClass);
|
||||
if (Stores.isMain(storeName)) {
|
||||
internalRegisterCreate(entity, masterEntityName, attributes);
|
||||
} else {
|
||||
// Create a new transaction in main DB if we are saving an entity from additional data store
|
||||
try (Transaction tx = persistence.createTransaction()) {
|
||||
internalRegisterCreate(entity, masterEntityName, attributes);
|
||||
tx.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@ -340,7 +362,13 @@ public class EntityLog implements EntityLogAPI {
|
||||
protected Set<String> filterRemovedAttributes(MetaClass metaClass, Set<String> attributes) {
|
||||
// filter attributes that do not exists in entity anymore
|
||||
return attributes.stream()
|
||||
.filter(attributeName -> metaClass.getProperty(attributeName) != null)
|
||||
.filter(attributeName -> {
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(attributeName)){
|
||||
return DynamicAttributesUtils.getMetaPropertyPath(metaClass, attributeName) != null;
|
||||
} else {
|
||||
return metaClass.getProperty(attributeName) != null;
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@ -354,11 +382,42 @@ public class EntityLog implements EntityLogAPI {
|
||||
item.setType(EntityLogItem.Type.CREATE);
|
||||
item.setEntity(entityName);
|
||||
item.setObjectEntityId(referenceToEntitySupport.getReferenceId(entity));
|
||||
item.setAttributes(createAttributes(entity, attributes, null));
|
||||
item.setAttributes(createLogAttributes(entity, attributes, null));
|
||||
|
||||
enqueueItem(item);
|
||||
}
|
||||
|
||||
protected void internalRegisterModifyAttributeValue(CategoryAttributeValue entity, @Nullable EntityAttributeChanges changes,
|
||||
Set<String> attributes) {
|
||||
String propertyName = DynamicAttributesUtils.encodeAttributeCode(entity.getCode());
|
||||
if (!attributes.contains(propertyName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Date ts = timeSource.currentTimestamp();
|
||||
EntityManager em = persistence.getEntityManager();
|
||||
|
||||
Set<String> dirty;
|
||||
if (changes == null) {
|
||||
dirty = persistence.getTools().getDirtyFields(entity);
|
||||
} else {
|
||||
dirty = changes.getAttributes();
|
||||
}
|
||||
boolean registerDeleteOp = dirty.contains("deleteTs") && entity.isDeleted();
|
||||
boolean hasChanges = dirty.stream().anyMatch(s -> s.endsWith("Value"));
|
||||
if (hasChanges) {
|
||||
EntityLogItem item = metadata.create(EntityLogItem.class);
|
||||
item.setEventTs(ts);
|
||||
item.setUser(findUser(em));
|
||||
item.setType(EntityLogItem.Type.MODIFY);
|
||||
item.setEntity(getEntityName(entity));
|
||||
item.setObjectEntityId(entity.getObjectEntityId());
|
||||
item.setAttributes(createDynamicLogAttribute(entity, changes, registerDeleteOp));
|
||||
|
||||
enqueueItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
protected User findUser(EntityManager em) {
|
||||
if (AppContext.isStarted())
|
||||
return em.getReference(User.class, userSessionSource.getUserSession().getUser().getId());
|
||||
@ -400,8 +459,9 @@ public class EntityLog implements EntityLogAPI {
|
||||
if (doNotRegister(entity))
|
||||
return;
|
||||
|
||||
String entityName = getEntityName(entity);
|
||||
Set<String> attributes = getLoggedAttributes(entityName, auto);
|
||||
String masterEntityName = getEntityName(entity);
|
||||
boolean isCategoryAttributeValue = entity instanceof CategoryAttributeValue;
|
||||
Set<String> attributes = getLoggedAttributes(masterEntityName, auto);
|
||||
if (attributes != null && attributes.contains("*")) {
|
||||
attributes = getAllAttributes(entity);
|
||||
}
|
||||
@ -409,17 +469,21 @@ public class EntityLog implements EntityLogAPI {
|
||||
return;
|
||||
}
|
||||
|
||||
MetaClass metaClass = metadata.getClassNN(entityName);
|
||||
MetaClass metaClass = metadata.getClassNN(masterEntityName);
|
||||
attributes = filterRemovedAttributes(metaClass, attributes);
|
||||
|
||||
String storeName = metadataTools.getStoreName(metaClass);
|
||||
if (Stores.isMain(storeName)) {
|
||||
internalRegisterModify(entity, changes, metaClass, storeName, attributes);
|
||||
if (isCategoryAttributeValue) {
|
||||
internalRegisterModifyAttributeValue((CategoryAttributeValue) entity, changes, attributes);
|
||||
} else {
|
||||
// Create a new transaction in main DB if we are saving an entity from additional data store
|
||||
try (Transaction tx = persistence.createTransaction()) {
|
||||
String storeName = metadataTools.getStoreName(metaClass);
|
||||
if (Stores.isMain(storeName)) {
|
||||
internalRegisterModify(entity, changes, metaClass, storeName, attributes);
|
||||
tx.commit();
|
||||
} else {
|
||||
// Create a new transaction in main DB if we are saving an entity from additional data store
|
||||
try (Transaction tx = persistence.createTransaction()) {
|
||||
internalRegisterModify(entity, changes, metaClass, storeName, attributes);
|
||||
tx.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@ -443,7 +507,7 @@ public class EntityLog implements EntityLogAPI {
|
||||
EntityLogItem.Type type;
|
||||
if (entity instanceof SoftDelete && dirty.contains("deleteTs") && !((SoftDelete) entity).isDeleted()) {
|
||||
type = EntityLogItem.Type.RESTORE;
|
||||
entityLogAttrs = createAttributes(entity, attributes, changes);
|
||||
entityLogAttrs = createLogAttributes(entity, attributes, changes);
|
||||
} else {
|
||||
type = EntityLogItem.Type.MODIFY;
|
||||
Set<String> dirtyAttributes = new HashSet<>();
|
||||
@ -457,7 +521,7 @@ public class EntityLog implements EntityLogAPI {
|
||||
}
|
||||
}
|
||||
}
|
||||
entityLogAttrs = createAttributes(entity, dirtyAttributes, changes);
|
||||
entityLogAttrs = createLogAttributes(entity, dirtyAttributes, changes);
|
||||
}
|
||||
if (!entityLogAttrs.isEmpty() || type == EntityLogItem.Type.RESTORE) {
|
||||
EntityLogItem item = metadata.create(EntityLogItem.class);
|
||||
@ -472,10 +536,13 @@ public class EntityLog implements EntityLogAPI {
|
||||
}
|
||||
}
|
||||
|
||||
private Set<EntityLogAttr> createAttributes(Entity entity, Set<String> attributes,
|
||||
@Nullable EntityAttributeChanges changes) {
|
||||
protected Set<EntityLogAttr> createLogAttributes(Entity entity, Set<String> attributes,
|
||||
@Nullable EntityAttributeChanges changes) {
|
||||
Set<EntityLogAttr> result = new HashSet<>();
|
||||
for (String name : attributes) {
|
||||
if (DynamicAttributesUtils.isDynamicAttribute(name)) {
|
||||
continue;
|
||||
}
|
||||
EntityLogAttr attr = metadata.create(EntityLogAttr.class);
|
||||
attr.setName(name);
|
||||
|
||||
@ -505,6 +572,30 @@ public class EntityLog implements EntityLogAPI {
|
||||
return result;
|
||||
}
|
||||
|
||||
protected Set<EntityLogAttr> createDynamicLogAttribute(CategoryAttributeValue entity, @Nullable EntityAttributeChanges changes, boolean registerDeleteOp) {
|
||||
Set<EntityLogAttr> result = new HashSet<>();
|
||||
EntityLogAttr attr = metadata.create(EntityLogAttr.class);
|
||||
attr.setName(DynamicAttributesUtils.encodeAttributeCode(entity.getCode()));
|
||||
|
||||
Object value = entity.getValue();
|
||||
attr.setValue(stringify(value));
|
||||
|
||||
Object valueId = getValueId(value);
|
||||
if (valueId != null)
|
||||
attr.setValueId(valueId.toString());
|
||||
|
||||
if (changes != null || registerDeleteOp) {
|
||||
Object oldValue = getOldCategoryAttributeValue(entity, changes);
|
||||
attr.setOldValue(stringify(oldValue));
|
||||
Object oldValueId = getValueId(oldValue);
|
||||
if (oldValueId != null) {
|
||||
attr.setOldValueId(oldValueId.toString());
|
||||
}
|
||||
}
|
||||
result.add(attr);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected String getChanges(Properties properties) {
|
||||
try {
|
||||
StringWriter writer = new StringWriter();
|
||||
@ -529,8 +620,9 @@ public class EntityLog implements EntityLogAPI {
|
||||
if (doNotRegister(entity))
|
||||
return;
|
||||
|
||||
String entityName = getEntityName(entity);
|
||||
Set<String> attributes = getLoggedAttributes(entityName, auto);
|
||||
String masterEntityName = getEntityName(entity);
|
||||
boolean isCategoryAttributeValue = entity instanceof CategoryAttributeValue;
|
||||
Set<String> attributes = getLoggedAttributes(masterEntityName, auto);
|
||||
if (attributes != null && attributes.contains("*")) {
|
||||
attributes = getAllAttributes(entity);
|
||||
}
|
||||
@ -538,17 +630,20 @@ public class EntityLog implements EntityLogAPI {
|
||||
return;
|
||||
}
|
||||
|
||||
MetaClass metaClass = metadata.getClassNN(entityName);
|
||||
MetaClass metaClass = metadata.getClassNN(masterEntityName);
|
||||
attributes = filterRemovedAttributes(metaClass, attributes);
|
||||
|
||||
String storeName = metadata.getTools().getStoreName(metaClass);
|
||||
if (Stores.isMain(storeName)) {
|
||||
internalRegisterDelete(entity, entityName, attributes);
|
||||
if (isCategoryAttributeValue) {
|
||||
internalRegisterModifyAttributeValue((CategoryAttributeValue) entity, null, attributes);
|
||||
} else {
|
||||
// Create a new transaction in main DB if we are saving an entity from additional data store
|
||||
try (Transaction tx = persistence.createTransaction()) {
|
||||
internalRegisterDelete(entity, entityName, attributes);
|
||||
tx.commit();
|
||||
String storeName = metadata.getTools().getStoreName(metaClass);
|
||||
if (Stores.isMain(storeName)) {
|
||||
internalRegisterDelete(entity, masterEntityName, attributes);
|
||||
} else {
|
||||
// Create a new transaction in main DB if we are saving an entity from additional data store
|
||||
try (Transaction tx = persistence.createTransaction()) {
|
||||
internalRegisterDelete(entity, masterEntityName, attributes);
|
||||
tx.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@ -566,7 +661,7 @@ public class EntityLog implements EntityLogAPI {
|
||||
item.setType(EntityLogItem.Type.DELETE);
|
||||
item.setEntity(entityName);
|
||||
item.setObjectEntityId(referenceToEntitySupport.getReferenceId(entity));
|
||||
item.setAttributes(createAttributes(entity, attributes, null));
|
||||
item.setAttributes(createLogAttributes(entity, attributes, null));
|
||||
|
||||
enqueueItem(item);
|
||||
}
|
||||
@ -576,13 +671,23 @@ public class EntityLog implements EntityLogAPI {
|
||||
return null;
|
||||
}
|
||||
Set<String> attributes = new HashSet<>();
|
||||
for (MetaProperty metaProperty : metadata.getClassNN(entity.getClass()).getProperties()) {
|
||||
MetaClass metaClass = metadata.getClassNN(entity.getClass());
|
||||
for (MetaProperty metaProperty : metaClass.getProperties()) {
|
||||
Range range = metaProperty.getRange();
|
||||
if (range.isClass() && range.getCardinality().isMany()) {
|
||||
continue;
|
||||
}
|
||||
attributes.add(metaProperty.getName());
|
||||
}
|
||||
Collection<CategoryAttribute> categoryAttributes = dynamicAttributes.getAttributesForMetaClass(metaClass);
|
||||
if (categoryAttributes != null) {
|
||||
for (CategoryAttribute categoryAttribute : categoryAttributes) {
|
||||
if (BooleanUtils.isNotTrue(categoryAttribute.getIsCollection())) {
|
||||
attributes.add(
|
||||
DynamicAttributesUtils.getMetaPropertyPath(metaClass, categoryAttribute).getMetaProperty().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@ -618,6 +723,35 @@ public class EntityLog implements EntityLogAPI {
|
||||
}
|
||||
}
|
||||
|
||||
protected Object getOldCategoryAttributeValue(CategoryAttributeValue attributeValue, EntityAttributeChanges changes) {
|
||||
CategoryAttribute categoryAttribute = attributeValue.getCategoryAttribute();
|
||||
PersistenceTools persistenceTools = persistence.getTools();
|
||||
String fieldName = null;
|
||||
switch (categoryAttribute.getDataType()) {
|
||||
case DATE:
|
||||
fieldName = "dateValue";
|
||||
break;
|
||||
case ENUMERATION:
|
||||
case STRING:
|
||||
fieldName = "stringValue";
|
||||
break;
|
||||
case INTEGER:
|
||||
fieldName = "intValue";
|
||||
break;
|
||||
case DOUBLE:
|
||||
fieldName = "doubleValue";
|
||||
break;
|
||||
case BOOLEAN:
|
||||
fieldName = "booleanValue";
|
||||
break;
|
||||
}
|
||||
if (fieldName != null) {
|
||||
return changes != null ? changes.getOldValue(fieldName) :
|
||||
persistenceTools.getOldValue(attributeValue, fieldName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void logError(Entity entity, Exception e) {
|
||||
log.warn("Unable to log entity {}, id={}", entity, entity.getId(), e);
|
||||
}
|
||||
|
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2017 Haulmont.
|
||||
*
|
||||
* 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 spec.cuba.core.entity_log
|
||||
|
||||
import com.haulmont.bali.db.QueryRunner
|
||||
import com.haulmont.cuba.core.EntityManager
|
||||
import com.haulmont.cuba.core.Query
|
||||
import com.haulmont.cuba.core.Transaction
|
||||
import com.haulmont.cuba.core.TypedQuery
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesManagerAPI
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.PropertyType
|
||||
import com.haulmont.cuba.core.entity.Category
|
||||
import com.haulmont.cuba.core.entity.CategoryAttribute
|
||||
import com.haulmont.cuba.core.entity.ReferenceToEntity
|
||||
import com.haulmont.cuba.core.global.AppBeans
|
||||
import com.haulmont.cuba.core.global.DataManager
|
||||
import com.haulmont.cuba.core.global.LoadContext
|
||||
import com.haulmont.cuba.core.global.View
|
||||
import com.haulmont.cuba.security.app.EntityLogAPI
|
||||
import com.haulmont.cuba.security.entity.*
|
||||
import com.haulmont.cuba.testsupport.TestContainer
|
||||
import com.haulmont.cuba.testsupport.TestSupport
|
||||
import org.junit.ClassRule
|
||||
import spock.lang.Shared
|
||||
import spock.lang.Specification
|
||||
|
||||
import java.sql.SQLException
|
||||
|
||||
class EntityLogDynamicAttributesTest extends Specification {
|
||||
|
||||
@Shared @ClassRule
|
||||
public TestContainer cont = TestContainer.Common.INSTANCE
|
||||
|
||||
private UUID user1Id, categoryId, categoryAttributeId
|
||||
private def entityLog
|
||||
private DataManager dataManager
|
||||
private def dynamicAttributesManagerAPI
|
||||
|
||||
|
||||
void setup() {
|
||||
_cleanup()
|
||||
|
||||
cont.persistence().runInTransaction { em ->
|
||||
Query q
|
||||
q = em.createNativeQuery("delete from SEC_ENTITY_LOG")
|
||||
q.executeUpdate()
|
||||
|
||||
q = em.createNativeQuery("delete from SYS_ATTR_VALUE")
|
||||
q.executeUpdate()
|
||||
|
||||
LoggedEntity le = new LoggedEntity()
|
||||
le.setName('sec$User')
|
||||
le.setAuto(true)
|
||||
em.persist(le)
|
||||
|
||||
LoggedAttribute la = new LoggedAttribute()
|
||||
la.setEntity(le)
|
||||
la.setName('name')
|
||||
em.persist(la)
|
||||
|
||||
la = new LoggedAttribute()
|
||||
la.setEntity(le)
|
||||
la.setName('+userAttribute')
|
||||
em.persist(la)
|
||||
|
||||
Category category = new Category()
|
||||
category.setName("user")
|
||||
category.setEntityType("sec\$User")
|
||||
categoryId = category.getId()
|
||||
em.persist(category)
|
||||
|
||||
CategoryAttribute categoryAttribute = new CategoryAttribute()
|
||||
categoryAttribute.setName("userAttribute")
|
||||
categoryAttribute.setCode("userAttribute")
|
||||
categoryAttribute.setCategory(category)
|
||||
categoryAttribute.setCategoryEntityType("sec\$User")
|
||||
categoryAttribute.setDataType(PropertyType.STRING)
|
||||
categoryAttribute.setDefaultEntity(new ReferenceToEntity())
|
||||
categoryAttributeId = categoryAttribute.getId()
|
||||
em.persist(categoryAttribute)
|
||||
|
||||
}
|
||||
entityLog = AppBeans.get(EntityLogAPI.class)
|
||||
entityLog.invalidateCache()
|
||||
dynamicAttributesManagerAPI = AppBeans.get(DynamicAttributesManagerAPI.class)
|
||||
dynamicAttributesManagerAPI.loadCache()
|
||||
dataManager = AppBeans.get(DataManager.class)
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
_cleanup()
|
||||
if (user1Id != null)
|
||||
cont.deleteRecord("SEC_USER", user1Id)
|
||||
|
||||
cont.deleteRecord("SYS_CATEGORY_ATTR", categoryAttributeId)
|
||||
cont.deleteRecord("SYS_CATEGORY", categoryId)
|
||||
}
|
||||
|
||||
private void _cleanup() throws SQLException {
|
||||
QueryRunner runner = new QueryRunner(cont.persistence().getDataSource())
|
||||
runner.update("delete from SEC_LOGGED_ATTR")
|
||||
runner.update("delete from SEC_LOGGED_ENTITY")
|
||||
runner.update("delete from SYS_ATTR_VALUE")
|
||||
}
|
||||
|
||||
private List<EntityLogItem> getEntityLogItems(def userId) {
|
||||
Transaction tx
|
||||
List<EntityLogItem> items
|
||||
tx = cont.persistence().createTransaction()
|
||||
try {
|
||||
EntityManager em = cont.persistence().getEntityManager()
|
||||
TypedQuery<EntityLogItem> query = em.createQuery(
|
||||
'select i from sec$EntityLog i where i.entity = ?1 and i.entityRef.entityId = ?2 order by i.eventTs desc', EntityLogItem.class)
|
||||
query.setParameter(1, 'sec$User')
|
||||
query.setParameter(2, userId)
|
||||
items = query.getResultList()
|
||||
|
||||
tx.commit()
|
||||
} finally {
|
||||
tx.end()
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
def "Entity Log: create/update/delete entity with dynamic attribute"() {
|
||||
Group group = cont.persistence().callInTransaction({ em ->
|
||||
em.find(Group.class, TestSupport.COMPANY_GROUP_ID)
|
||||
})
|
||||
|
||||
when:
|
||||
|
||||
User user1 = cont.metadata().create(User)
|
||||
user1Id = user1.getId()
|
||||
user1.setGroup(group)
|
||||
user1.setLogin("test")
|
||||
user1.setName("test-name")
|
||||
user1.getValue("+userAttribute")
|
||||
user1.setValue("+userAttribute", "userName")
|
||||
|
||||
dataManager.commit(user1)
|
||||
|
||||
then:
|
||||
|
||||
def items = getEntityLogItems(user1Id)
|
||||
items.size() == 1
|
||||
def item = items[0]
|
||||
|
||||
item.type == EntityLogItem.Type.CREATE
|
||||
item.attributes.find({ it.name == 'name' }).value == 'test-name'
|
||||
item.attributes.find({ it.name == '+userAttribute' }).value == 'userName'
|
||||
|
||||
when:
|
||||
|
||||
LoadContext<User> loadContext = new LoadContext(User.class)
|
||||
.setId(user1).setView(View.LOCAL).setLoadDynamicAttributes(true)
|
||||
user1 = dataManager.load(loadContext)
|
||||
user1Id = user1.getId()
|
||||
user1.setValue("+userAttribute", "userName1")
|
||||
|
||||
dataManager.commit(user1)
|
||||
|
||||
then:
|
||||
|
||||
def items1 = getEntityLogItems(user1Id)
|
||||
items1.size() == 2
|
||||
def item1 = items1[0]
|
||||
|
||||
item1.type == EntityLogItem.Type.MODIFY
|
||||
item1.attributes.find({ it.name == '+userAttribute' }).oldValue == 'userName'
|
||||
item1.attributes.find({ it.name == '+userAttribute' }).value == 'userName1'
|
||||
|
||||
when:
|
||||
|
||||
loadContext = new LoadContext(User.class)
|
||||
.setId(user1).setView(View.LOCAL).setLoadDynamicAttributes(true)
|
||||
user1 = (User) dataManager.load(loadContext)
|
||||
user1Id = user1.getId()
|
||||
user1.setValue("+userAttribute", null)
|
||||
|
||||
dataManager.commit(user1)
|
||||
|
||||
then:
|
||||
|
||||
def items2 = getEntityLogItems(user1Id)
|
||||
items2.size() == 3
|
||||
def item2 = items2[0]
|
||||
|
||||
item2.type == EntityLogItem.Type.MODIFY
|
||||
item2.attributes.find({ it.name == '+userAttribute' }).value == ""
|
||||
item2.attributes.find({ it.name == '+userAttribute' }).oldValue == 'userName1'
|
||||
}
|
||||
}
|
@ -20,8 +20,12 @@ package com.haulmont.cuba.gui.app.core.entitylog;
|
||||
import com.haulmont.bali.util.ParamsMap;
|
||||
import com.haulmont.chile.core.model.MetaClass;
|
||||
import com.haulmont.chile.core.model.MetaProperty;
|
||||
import com.haulmont.chile.core.model.MetaPropertyPath;
|
||||
import com.haulmont.chile.core.model.Range;
|
||||
import com.haulmont.cuba.core.app.EntityLogService;
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributes;
|
||||
import com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesUtils;
|
||||
import com.haulmont.cuba.core.entity.CategoryAttribute;
|
||||
import com.haulmont.cuba.core.entity.Entity;
|
||||
import com.haulmont.cuba.core.entity.HasUuid;
|
||||
import com.haulmont.cuba.core.global.AppBeans;
|
||||
@ -37,6 +41,7 @@ import com.haulmont.cuba.gui.data.CollectionDatasource;
|
||||
import com.haulmont.cuba.gui.theme.ThemeConstants;
|
||||
import com.haulmont.cuba.gui.xml.layout.ComponentsFactory;
|
||||
import com.haulmont.cuba.security.entity.*;
|
||||
import org.apache.commons.lang.BooleanUtils;
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@ -62,6 +67,9 @@ public class EntityLogBrowser extends AbstractWindow {
|
||||
@Inject
|
||||
protected ReferenceToEntitySupport referenceToEntitySupport;
|
||||
|
||||
@Inject
|
||||
protected DynamicAttributes dynamicAttributes;
|
||||
|
||||
@Inject
|
||||
protected CollectionDatasource<EntityLogItem, UUID> entityLogDs;
|
||||
|
||||
@ -306,43 +314,49 @@ public class EntityLogBrowser extends AbstractWindow {
|
||||
actionsPaneLayout.setVisible(false);
|
||||
}
|
||||
|
||||
protected void fillAttributes(String metaClassName, LoggedEntity item, boolean setEditableCheckboxes) {
|
||||
protected void fillAttributes(String metaClassName, LoggedEntity item, boolean editable) {
|
||||
clearAttributes();
|
||||
setSelectAllCheckBox(false);
|
||||
|
||||
if (metaClassName != null) {
|
||||
MetaClass metaClass = metadata.getExtendedEntities().getEffectiveMetaClass(
|
||||
metadata.getClassNN(metaClassName));
|
||||
Collection<MetaProperty> metaProperties = metaClass.getProperties();
|
||||
selectAllCheckBox.setEditable(setEditableCheckboxes);
|
||||
List<MetaProperty> metaProperties = new ArrayList<>(metaClass.getProperties());
|
||||
selectAllCheckBox.setEditable(editable);
|
||||
Set<LoggedAttribute> enabledAttr = null;
|
||||
if (item != null)
|
||||
enabledAttr = item.getAttributes();
|
||||
for (MetaProperty property : metaProperties) {
|
||||
if (!systemAttrsList.contains(property.getName())) {
|
||||
Range range = property.getRange();
|
||||
if (range.isClass() && metadata.getTools().hasCompositePrimaryKey(range.asClass()) &&
|
||||
!HasUuid.class.isAssignableFrom(range.asClass().getJavaClass())) {
|
||||
continue;
|
||||
if (allowLogProperty(property, null)) {
|
||||
addAttribute(enabledAttr, property, editable);
|
||||
}
|
||||
}
|
||||
Collection<CategoryAttribute> attributes = dynamicAttributes.getAttributesForMetaClass(metaClass);
|
||||
if (attributes != null) {
|
||||
for (CategoryAttribute categoryAttribute : attributes) {
|
||||
MetaPropertyPath propertyPath = DynamicAttributesUtils.getMetaPropertyPath(metaClass, categoryAttribute);
|
||||
MetaProperty property = propertyPath.getMetaProperty();
|
||||
if (allowLogProperty(property, categoryAttribute)) {
|
||||
addAttribute(enabledAttr, property, editable);
|
||||
}
|
||||
if (range.isClass() && range.getCardinality().isMany()) {
|
||||
continue;
|
||||
}
|
||||
CheckBox checkBox = factory.createComponent(CheckBox.class);
|
||||
if (enabledAttr != null && isEntityHaveAttribute(property.getName(), enabledAttr)) {
|
||||
checkBox.setValue(true);
|
||||
}
|
||||
checkBox.setId(property.getName());
|
||||
checkBox.setCaption(property.getName());
|
||||
checkBox.setEditable(setEditableCheckboxes);
|
||||
checkBox.addValueChangeListener(e -> checkAllCheckboxes());
|
||||
|
||||
attributesBoxScroll.add(checkBox);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void addAttribute(Set<LoggedAttribute> enabledAttributes, MetaProperty property, boolean editable) {
|
||||
CheckBox checkBox = factory.createComponent(CheckBox.class);
|
||||
if (enabledAttributes != null && isEntityHaveAttribute(property.getName(), enabledAttributes)) {
|
||||
checkBox.setValue(true);
|
||||
}
|
||||
checkBox.setId(property.getName());
|
||||
checkBox.setCaption(property.getName());
|
||||
checkBox.setEditable(editable);
|
||||
checkBox.addValueChangeListener(e -> checkAllCheckboxes());
|
||||
|
||||
attributesBoxScroll.add(checkBox);
|
||||
}
|
||||
|
||||
protected void enableAllCheckBoxes(boolean b) {
|
||||
if (canSelectAllCheckboxGenerateEvents) {
|
||||
for (Component box : attributesBoxScroll.getComponents())
|
||||
@ -474,6 +488,25 @@ public class EntityLogBrowser extends AbstractWindow {
|
||||
cancelBtn.requestFocus();
|
||||
}
|
||||
|
||||
protected boolean allowLogProperty(MetaProperty metaProperty, CategoryAttribute categoryAttribute) {
|
||||
if (systemAttrsList.contains(metaProperty.getName())) {
|
||||
return false;
|
||||
}
|
||||
Range range = metaProperty.getRange();
|
||||
if (range.isClass() && metadata.getTools().hasCompositePrimaryKey(range.asClass()) &&
|
||||
!HasUuid.class.isAssignableFrom(range.asClass().getJavaClass())) {
|
||||
return false;
|
||||
}
|
||||
if (range.isClass() && range.getCardinality().isMany()) {
|
||||
return false;
|
||||
}
|
||||
if (categoryAttribute != null &&
|
||||
BooleanUtils.isTrue(categoryAttribute.getIsCollection())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected class SaveAction extends AbstractAction {
|
||||
|
||||
public SaveAction() {
|
||||
|
Loading…
Reference in New Issue
Block a user