Skip to content

Commit

Permalink
Merge pull request #42 from 9ci/41-created-date-reset-issue
Browse files Browse the repository at this point in the history
Fix #41 - Created date should not get reset
  • Loading branch information
snimavat authored Oct 6, 2017
2 parents c4e8cbf + 49e5ae7 commit 5b30633
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 30 deletions.
2 changes: 1 addition & 1 deletion AuditTrailGrailsPlugin.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import grails.plugin.audittrail.AuditTrailHelper
import grails.plugin.audittrail.AuditTrailInterceptor

class AuditTrailGrailsPlugin {
def version = "2.1.2"
def version = "2.1.3"
def grailsVersion = "2.0.0 > *"

def author = "Joshua Burnett"
Expand Down
41 changes: 31 additions & 10 deletions src/groovy/grails/plugin/audittrail/AuditTrailHelper.groovy
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package grails.plugin.audittrail

import gorm.FieldProps
import org.apache.log4j.Logger
import org.codehaus.groovy.grails.commons.GrailsApplication
import org.springframework.beans.factory.InitializingBean
Expand Down Expand Up @@ -33,12 +34,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 ->
[FieldProps.CREATED_DATE_KEY, FieldProps.EDITED_DATE_KEY].each { key ->
setDateField(entity, key, time)
}
['createdBy', 'editedBy'].each { key ->

[FieldProps.CREATED_BY_KEY, FieldProps.EDITED_BY_KEY].each { key ->
setUserField(entity, key)
}
}
Expand All @@ -55,21 +57,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(FieldProps.CREATED_DATE_KEY).name
MetaProperty createdDateProperty = entity.hasProperty(createdDateFieldName)

//see issue#41
if(createdDateProperty != null) {
def existingValue = createdDateProperty.getProperty(entity)
return (existingValue == null)
} else {
def session = applicationContext.sessionFactory.currentSession
def entry = session.persistenceContext.getEntry(entity)
return !entry
}
}

boolean isDisableAuditStamp(entity) {
Expand Down
12 changes: 5 additions & 7 deletions src/groovy/grails/plugin/audittrail/AuditTrailInterceptor.groovy
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package grails.plugin.audittrail

import gorm.FieldProps
import org.apache.commons.lang.ArrayUtils
import org.apache.log4j.Logger
import org.hibernate.EmptyInterceptor
import org.hibernate.type.Type
import org.apache.log4j.Logger
import org.springframework.context.ApplicationContextAware
import org.springframework.context.ApplicationContext
import org.springframework.beans.factory.InitializingBean
import org.apache.commons.lang.ArrayUtils

class AuditTrailInterceptor extends EmptyInterceptor {
private static final Logger log = Logger.getLogger(AuditTrailInterceptor)
Expand Down Expand Up @@ -35,12 +33,12 @@ class AuditTrailInterceptor extends EmptyInterceptor {
if(disableAuditTrailStamp(entity)) return true

def time = System.currentTimeMillis()
['createdDate','editedDate'].each{ key->
[FieldProps.CREATED_DATE_KEY, FieldProps.EDITED_DATE_KEY].each{ key->
def valToSet = auditTrailHelper.setDateField(entity,key, time)
if(valToSet)
setValue(currentState, propertyNames, fieldPropsMap.get(key).name, valToSet)
}
['createdBy','editedBy'].each{ key->
[FieldProps.CREATED_BY_KEY, FieldProps.EDITED_BY_KEY].each{ key->
def valToSet = auditTrailHelper.setUserField(entity,key)
if(valToSet)
setValue(currentState, propertyNames, fieldPropsMap.get(key).name, valToSet)
Expand Down
8 changes: 4 additions & 4 deletions src/java/gorm/AuditStampASTTransformation.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ public void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
doBeforeValidate(classNode);
//debugFieldNodes(classNode);

createUserField( classNode, fprops.get("editedBy"));
createUserField( classNode, fprops.get("createdBy"));
createUserField( classNode, fprops.get(FieldProps.EDITED_BY_KEY));
createUserField( classNode, fprops.get(FieldProps.CREATED_BY_KEY));

createDateField( classNode, fprops.get("editedDate"));
createDateField( classNode, fprops.get("createdDate"));
createDateField( classNode, fprops.get(FieldProps.EDITED_DATE_KEY));
createDateField( classNode, fprops.get(FieldProps.CREATED_DATE_KEY));

}
}
Expand Down
16 changes: 11 additions & 5 deletions src/java/gorm/FieldProps.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@
class FieldProps {
private static final String DATE_CONS = "nullable:false, display:false, editable:false, bindable:false";
private static final String USER_CONS = "nullable:false, display:false, editable:false, bindable:false";


public static final String CREATED_DATE_KEY = "createdDate";
public static final String EDITED_DATE_KEY = "editedDate";
public static final String CREATED_BY_KEY = "createdBy";
public static final String EDITED_BY_KEY = "editedBy";


String name;
Class type;
//Object initValue;
Expand Down Expand Up @@ -51,11 +57,11 @@ public static FieldProps init(String defaultName,String defaultType, String defa

public static Map<String, FieldProps> buildFieldMap(ConfigObject config){
Map<String, FieldProps> map = new HashMap<String, FieldProps>();
map.put("createdBy",FieldProps.init("createdBy","java.lang.Long",USER_CONS,null,config));
map.put("editedBy",FieldProps.init("editedBy","java.lang.Long",USER_CONS,null,config));
map.put(CREATED_BY_KEY,FieldProps.init(CREATED_BY_KEY,"java.lang.Long",USER_CONS,null,config));
map.put(EDITED_BY_KEY,FieldProps.init(EDITED_BY_KEY,"java.lang.Long",USER_CONS,null,config));

map.put("editedDate",FieldProps.init("editedDate","java.util.Date",DATE_CONS,null,config));
map.put("createdDate",FieldProps.init("createdDate","java.util.Date",DATE_CONS,null,config));
map.put(EDITED_DATE_KEY,FieldProps.init(EDITED_DATE_KEY,"java.util.Date",DATE_CONS,null,config));
map.put(CREATED_DATE_KEY,FieldProps.init(CREATED_DATE_KEY,"java.util.Date",DATE_CONS,null,config));
return map;
}

Expand Down
45 changes: 43 additions & 2 deletions test/integration/nine/tests/AuditStampTests.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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")
}
Expand Down Expand Up @@ -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']
Expand Down
5 changes: 4 additions & 1 deletion test/integration/nine/tests/ChildDomTests.groovy
Original file line number Diff line number Diff line change
@@ -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
Expand Down

0 comments on commit 5b30633

Please sign in to comment.