From 46a449bfe34c070e0b9ae8e7803c89ac48cb5f77 Mon Sep 17 00:00:00 2001 From: sudhir nimavat Date: Fri, 6 Oct 2017 11:47:52 +0530 Subject: [PATCH] Fix #41 - Created date should not get reset when updating a detached object. --- .../plugin/audittrail/AuditTrailHelper.groovy | 27 ++++++++--- .../nine/tests/AuditStampTests.groovy | 45 ++++++++++++++++++- .../nine/tests/ChildDomTests.groovy | 5 ++- 3 files changed, 69 insertions(+), 8 deletions(-) diff --git a/src/groovy/grails/plugin/audittrail/AuditTrailHelper.groovy b/src/groovy/grails/plugin/audittrail/AuditTrailHelper.groovy index d2f9263..c731596 100644 --- a/src/groovy/grails/plugin/audittrail/AuditTrailHelper.groovy +++ b/src/groovy/grails/plugin/audittrail/AuditTrailHelper.groovy @@ -65,11 +65,28 @@ class AuditTrailHelper implements ApplicationContextAware, InitializingBean { return valToSet } - boolean isNewEntity(entity) { - - def session = applicationContext.sessionFactory.currentSession - def entry = session.persistenceContext.getEntry(entity) - return !entry + /** + * Checks if the given domain instance is new + * + * it first checks for the createdDate property, if property exists and is not null, returns false. + * else If createdDate property is not defined, it checks if the domain is attached to session and exists in persistence context. + * + * @param entity + * @return boolean + */ + boolean isNewEntity(def entity) { + String createdDateFieldName = fieldPropsMap.get("createdDate").name + MetaProperty createdDateProperty = entity.hasProperty(createdDateFieldName) + + //see issue#41 + if(createdDateProperty != null) { + Date existingValue = entity.getProperty(createdDateFieldName) + return (existingValue == null) + } else { + def session = applicationContext.sessionFactory.currentSession + def entry = session.persistenceContext.getEntry(entity) + return !entry + } } boolean isDisableAuditStamp(entity) { diff --git a/test/integration/nine/tests/AuditStampTests.groovy b/test/integration/nine/tests/AuditStampTests.groovy index 3202f09..298a16f 100644 --- a/test/integration/nine/tests/AuditStampTests.groovy +++ b/test/integration/nine/tests/AuditStampTests.groovy @@ -6,11 +6,13 @@ import grails.test.mixin.integration.IntegrationTestMixin import groovy.sql.Sql import org.apache.commons.lang.time.DateUtils import org.codehaus.groovy.grails.commons.GrailsApplication +import org.codehaus.groovy.grails.plugins.DomainClassGrailsPlugin import org.codehaus.groovy.grails.web.binding.DefaultASTDatabindingHelper import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.core.authority.AuthorityUtils import org.springframework.security.core.context.SecurityContextHolder import org.springframework.security.core.context.SecurityContextHolder as SCH +import spock.lang.Issue /** * Uses the doms domain to test the created by and edited by fields and CreateEditeStamp ASTrandformer @@ -53,8 +55,11 @@ class AuditStampTests { assert art.constraints.updatedBy.getAppliedConstraint('max').maxValue == 90000l def l = TestDomain."${DefaultASTDatabindingHelper.DEFAULT_DATABINDING_WHITELIST}" - assert l == ['name'] - assert l.size() == 1 + assert l.contains("name") + assert !l.contains("createdDate") + assert !l.contains("createdBy") + assert !l.contains("editedDate") + assert !l.contains("updatedBy") //def prop= art.getPropertyByName("updatedBy") } @@ -144,6 +149,42 @@ class AuditStampTests { assert authUser.id == data.whoUpdated } + @Issue("https://github.com/9ci/grails-audit-trail/issues/41") + void test_update_doesnot_change_createdDate_when_session_is_cleared() { + Date today = new Date() + Date yesterday = today - 1 + java.sql.Date yesterdaySQL = new java.sql.Date(yesterday.getTime()) + Sql sql = new Sql(sessionFactory.getCurrentSession().connection()) + + sql.execute("insert into TestDomains (oid,version,name, createdBy, createdDate, whoUpdated, editedDate) "+ + " values (?,?,?,?,?,?,?)", [2,0,"xxx", 0, yesterdaySQL,0, yesterdaySQL]) + + + TestDomain dom = TestDomain.get(2) + assert dom != null + dom.name="new name" + + //clear session to test that createdDate does not get reset for detached objects. + sessionFactory.currentSession.clear() + DomainClassGrailsPlugin.PROPERTY_INSTANCE_MAP.get().clear() + + dom.save(flush:true,failOnError:true) + + String sqlCall = 'select oid, createdBy, createdDate, whoUpdated, editedDate from TestDomains where oid = ' + dom.id + + Map data = sql.firstRow(sqlCall) + assert data != null + assert dom.id == data.oid + assert data.editedDate != null + assert data.createdDate != null + + assert DateUtils.isSameDay(data.editedDate, new Date()), "edited Date should have been set to today" + assert DateUtils.isSameDay(data.createdDate, yesterday), "Created date should have been changed" + + def authUser = login() + assert authUser.id == data.whoUpdated + } + void test_disableAuditTrailStamp_fail(){ def d = new TestDomain() d.properties = [name:'test'] diff --git a/test/integration/nine/tests/ChildDomTests.groovy b/test/integration/nine/tests/ChildDomTests.groovy index a3d28b8..e38b6f9 100644 --- a/test/integration/nine/tests/ChildDomTests.groovy +++ b/test/integration/nine/tests/ChildDomTests.groovy @@ -1,11 +1,14 @@ package nine.tests +import org.codehaus.groovy.grails.commons.DefaultGrailsDomainClass +import org.codehaus.groovy.grails.commons.GrailsDomainClass + class ChildDomTests extends BaseInt { def grailsApplication void testConstaints() { - def art = grailsApplication.getDomainClass("nine.tests.ChildDom") + DefaultGrailsDomainClass art = grailsApplication.getDomainClass("nine.tests.ChildDom") assert art assert art.constraints.childProp.getAppliedConstraint('nullable').isNullable() == false assert art.constraints.childProp.getAppliedConstraint('blank').isBlank() == false