Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #41 - Created date should not get reset #42

Merged
merged 5 commits into from
Oct 6, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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