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

Implement a way to use custom stampable type #199

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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 examples/audit-test/grails-app/domain/test/Coach.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package test

import grails.plugins.orm.auditable.Stampable

class Coach implements Stampable {
class Coach implements Stampable<Date, Coach> {

static constraints = {
}
Expand Down
6 changes: 3 additions & 3 deletions examples/audit-test/grails-app/domain/test/Train.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ package test

import grails.plugins.orm.auditable.Stampable

class Train implements Stampable {
String number
class Train implements Stampable<Date, Train> {
String number

static constraints = {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ class AuditLogListener extends AbstractPersistenceEventListener {
catch (Exception e) {
if (AuditLogContext.context.failOnError) {
throw e
}
else {
} else {
log.error("Error creating audit log for event ${event.eventType} and domain ${event.entityObject}", e)
}
}
Expand All @@ -95,8 +94,8 @@ class AuditLogListener extends AbstractPersistenceEventListener {
@Override
boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return eventType.isAssignableFrom(PostInsertEvent) ||
eventType.isAssignableFrom(PreUpdateEvent) ||
eventType.isAssignableFrom(PreDeleteEvent)
eventType.isAssignableFrom(PreUpdateEvent) ||
eventType.isAssignableFrom(PreDeleteEvent)
}

/**
Expand All @@ -121,19 +120,18 @@ class AuditLogListener extends AbstractPersistenceEventListener {
if (map || !verbose) {
if (auditEventType == AuditEventType.DELETE) {
map = map.collectEntries { String property, Object value ->
// Accessing a hibernate PersistentCollection of a deleted entity yields a NPE in Grails 3.3.x.
// Accessing a hibernate PersistentCollection of a deleted entity yields a NPE in Grails 3.3.x.
// We can't filter hibernate classes because this plugin is ORM-agnostic and has no dependency to any ORM implementation.
// This is a workaround. We might not log some other ORM collection implementation even if it would be possible to log them.
// (see #153)
// TODO: Implement "nonVerboseDelete" switch in config (to only log the object id on delete)
if (value instanceof Collection) {
return [:]
}
return [(property):value]
return [(property): value]
} as Map<String, Object>
logChanges(domain, [:], map, auditEventType)
}
else {
} else {
logChanges(domain, map, [:], auditEventType)
}
}
Expand Down Expand Up @@ -189,7 +187,22 @@ class AuditLogListener extends AbstractPersistenceEventListener {

// Use a single date for all audit_log entries in this transaction
// Note, this will be ignored unless the audit_log domin has 'autoTimestamp false'
Date dateCreated = new Date()
Object dateCreated

if (eventType == AuditEventType.DELETE) {
if (oldMap.hasProperty("dateCreated")) {
Class<?> dateCreatedClass = oldMap.get("dateCreated").getClass()
dateCreated = dateCreatedClass.newInstance()
}
} else {
if (newMap.hasProperty("dateCreated")) {
Class<?> dateCreatedClass = newMap.get("dateCreated").getClass()
dateCreated = dateCreatedClass.newInstance()
}
}
if (dateCreated == null) {
dateCreated = new Date()
}

// This handles insert, delete, and update with any property level logging enabled
if (newMap || oldMap) {
Expand All @@ -208,24 +221,24 @@ class AuditLogListener extends AbstractPersistenceEventListener {
oldValueAsString = conditionallyMaskAndTruncate(domain, propertyName, domain.convertLoggedPropertyToString(propertyName, oldVal), truncateLength)
}


// Create a new entity for each property
GormEntity audit = createAuditLogDomainInstance(
actor: domain.logCurrentUserName, uri: domain.logURI, className: domain.logClassName, eventName: eventType.name(),
persistedObjectId: domain.logEntityId, persistedObjectVersion: persistedObjectVersion,
propertyName: propertyName, oldValue: oldValueAsString, newValue: newValueAsString,
dateCreated: dateCreated, lastUpdated: dateCreated
actor: domain.logCurrentUserName, uri: domain.logURI, className: domain.logClassName, eventName: eventType.name(),
persistedObjectId: domain.logEntityId, persistedObjectVersion: persistedObjectVersion,
propertyName: propertyName, oldValue: oldValueAsString, newValue: newValueAsString,
dateCreated: dateCreated, lastUpdated: dateCreated
)
if (domain.beforeSaveLog(audit)) {
audit.save(failOnError: true)
}
}
}
else {
} else {
// Create a single entity for this event
GormEntity audit = createAuditLogDomainInstance(
actor: domain.logCurrentUserName, uri: domain.logURI, className: domain.logClassName, eventName: eventType.name(),
persistedObjectId: domain.logEntityId, persistedObjectVersion: persistedObjectVersion,
dateCreated: dateCreated, lastUpdated: dateCreated
actor: domain.logCurrentUserName, uri: domain.logURI, className: domain.logClassName, eventName: eventType.name(),
persistedObjectId: domain.logEntityId, persistedObjectVersion: persistedObjectVersion,
dateCreated: dateCreated, lastUpdated: dateCreated
)
if (domain.beforeSaveLog(audit)) {
audit.save(failOnError: true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import org.grails.datastore.gorm.GormEntity
/**
* Entities should implement this trait to provide automatic stamping of date and user information
*/
trait Stampable<D> extends GormEntity<D> {
trait Stampable<T, D> extends GormEntity<D> {
// Grails will automatically populate these
Date dateCreated
Date lastUpdated
T dateCreated
T lastUpdated

// We initialize these to non-null to they pass initial validation, they are set on insert/update
String createdBy = "N/A"
Expand Down