From 61a6ceb62e84131b586ec734755154e5821891f6 Mon Sep 17 00:00:00 2001 From: sudhir nimavat Date: Fri, 6 Oct 2017 14:07:12 +0530 Subject: [PATCH] Fix #41 - Created date should not get reset when updating a detached object. --- audit-trail-plugin/build.gradle | 2 +- .../groovy/nine/tests/AuditStampSpec.groovy | 42 ++++++++++++++++- .../plugin/audittrail/AuditTrailHelper.groovy | 45 ++++++++++++++----- 3 files changed, 77 insertions(+), 12 deletions(-) diff --git a/audit-trail-plugin/build.gradle b/audit-trail-plugin/build.gradle index 83e0f43..871513e 100644 --- a/audit-trail-plugin/build.gradle +++ b/audit-trail-plugin/build.gradle @@ -9,7 +9,7 @@ buildscript { } } -version "3.0.4" +version "3.0.5" group "org.grails.plugins" apply plugin:"idea" diff --git a/audit-trail-plugin/src/integration-test/groovy/nine/tests/AuditStampSpec.groovy b/audit-trail-plugin/src/integration-test/groovy/nine/tests/AuditStampSpec.groovy index 1b239be..8bb753a 100644 --- a/audit-trail-plugin/src/integration-test/groovy/nine/tests/AuditStampSpec.groovy +++ b/audit-trail-plugin/src/integration-test/groovy/nine/tests/AuditStampSpec.groovy @@ -5,7 +5,6 @@ import grails.plugin.springsecurity.SpringSecurityService import grails.plugin.springsecurity.userdetails.GrailsUser import grails.test.mixin.integration.Integration import grails.transaction.Rollback -import groovy.sql.GroovyResultSet import groovy.sql.GroovyRowResult import groovy.sql.Sql import org.apache.commons.lang.time.DateUtils @@ -16,6 +15,7 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio 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 import spock.lang.Specification import javax.sql.DataSource @@ -193,6 +193,46 @@ class AuditStampSpec extends Specification { assert currentUser.id == data.whoUpdated } + @Issue("https://github.com/9ci/grails-audit-trail/issues/41") + void "test pdate does not change createdDate when session is cleared"() { + setup: + 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]) + + + when: + TestDomain dom = TestDomain.get(2) + + then: + dom != null + + when: + dom.name="new name" + //clear session to test that createdDate does not get reset for detached objects. + sessionFactory.currentSession.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) + + then: + 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" + + } + void test_disableAuditTrailStamp_fail() { when: TestDomain d = new TestDomain() diff --git a/audit-trail-plugin/src/main/groovy/grails/plugin/audittrail/AuditTrailHelper.groovy b/audit-trail-plugin/src/main/groovy/grails/plugin/audittrail/AuditTrailHelper.groovy index e1ce4ac..e16ddd4 100644 --- a/audit-trail-plugin/src/main/groovy/grails/plugin/audittrail/AuditTrailHelper.groovy +++ b/audit-trail-plugin/src/main/groovy/grails/plugin/audittrail/AuditTrailHelper.groovy @@ -9,6 +9,11 @@ import org.springframework.context.ApplicationContextAware class AuditTrailHelper implements ApplicationContextAware, InitializingBean { private static final Logger log = Logger.getLogger(AuditTrailInterceptor) + private static final String CREATED_DATE_FIELD = "createdDate" + private static final String EDITED_DATE_FIELD = "editedDate" + private static final String CREATED_BY_FIELD = "createdBy" + private static final String EDITED_BY_FIELD = "editedBy" + Closure currentUserClosure //injected @@ -33,12 +38,13 @@ class AuditTrailHelper implements ApplicationContextAware, InitializingBean { } void setFieldDefaults(Object entity) { - def time = System.currentTimeMillis() + Long time = System.currentTimeMillis() //assume its a new entity - ['createdDate', 'editedDate'].each { key -> + [CREATED_DATE_FIELD, EDITED_DATE_FIELD].each { key -> setDateField(entity, key, time) } - ['createdBy', 'editedBy'].each { key -> + + [CREATED_BY_FIELD, EDITED_BY_FIELD].each { key -> setUserField(entity, key) } } @@ -55,21 +61,40 @@ class AuditTrailHelper implements ApplicationContextAware, InitializingBean { } def setUserField(entity, String fieldName) { - def field = fieldPropsMap.get(fieldName).name - def property = entity.hasProperty(field) + String field = fieldPropsMap.get(fieldName).name + MetaProperty property = entity.hasProperty(field) + def valToSet if (property) { valToSet = currentUserId() entity.setProperty(field, valToSet) } + 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, true if null + * 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(CREATED_DATE_FIELD).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) {