Can't make Grails and audit-logging plugin work - grails

I'm trying to add data auditing to my Grails project, but it doesn't work. I've read this tutorial on grails site and did everything as described there.
What I have now is a domain class Event looking as simple as this:
class Event {
static auditable = true;
String name;
def onSave = {
println "event inserted";
}
def onChange = {
println "event changed";
}
}
and a method in the main controller:
def addEvent = {
def obj = new Event([name:"Test event 1"]);
if (obj.save(flush:true)){
render "addEvent complete for " + obj.toString();}
else{
render "addEvent failed for " + obj.toString();
obj.errors.allErrors.each {
log.error( it.toString() );
}
}
}
I also added auditLog.verbose = true to the Config.groovy file.
Still when I call this method from my browser, the new event is created in DB, but there is nothing in the audit_log table, nor in the console about this happening.
What am I missing here?

Related

Unable to bind Http Form data to HashMap collection

I am trying to post form data as
"student.id=1&courses[10].course.id=10"
The command object classes we are trying to bind are as below ...
class StudentEnrollmentCmd {
Student student
Map<String,CourseCmd> courses;
}
class CourseCmd {
CourseDomain course
}
class CourseDomain {
Long id
}
was hoping that it will bind to
"StudentEnrollmentCmd -> courses -> course.id"
which seems to work in grails 2.2.4 but fails in 3.3.7 with the following exception
No such property: course.id for class: student.CourseCmd
Here is the test case which illustrates the problem
void 'databinding from request parameters'() {
given:
// request with simple formdata: student.id=1&courses[10].course.id=10
MockHttpServletRequest request = buildMockRequestWithParams('POST',['student.id':'1','courses[10].course.id':'10']);
DataBindingSource source = bindingSourceCreator.createDataBindingSource(null,null,request);
// databinder & command object
def binder = new SimpleDataBinder()
def obj = new StudentEnrollmentCmd()
when:
binder.bind(obj,source)
then:
// this should not throw an exception, but throws an exception
MissingPropertyException ex = thrown()
System.out.println ( "Exception again:" + ex.message );
// the following should work, but does not work
obj.student.id == 1
obj.courses['10'].course.id == 10
}
Here is the link to full spec... https://github.com/swzaidi/sample/blob/master/grails3.3.7/src/test/groovy/student/DataBindingSpec.groovy
Looking for some help on how to pass the form data so that it binds to above command objects properly.

Grails i18n localization dynamically from database

Grails i18n From Database but Default Back To File
The below code is implemented based on the above link.
class DatabaseMessageSource extends PluginAwareResourceBundleMessageSource {
Ehcache messageCache
def messageBundleMessageSource
#Override
protected MessageFormat resolveCode(String code, Locale locale) {
println code + " : " + locale.language
def messageKey = new MessageKey(code, locale)
def messageFormat = messageCache.get(messageKey)?.value
if (!messageFormat) {
I18nMessage i18nMessage = I18nMessage.findByCodeAndLanguageCode(code, locale.language)
if (i18nMessage)
messageFormat = new MessageFormat(i18nMessage.text)
else
messageFormat = super.resolveCode(code, locale)
messageCache.put new Element(messageKey, messageFormat)
}
return messageFormat;
}
In the resources.groovy file this bean is configured as
shown in the below code.
beans = {
messageCache(EhCacheFactoryBean) {
timeToLive = 500
}
messageSource(DatabaseMessageSource) {
messageCache = messageCache
basename = "WEB-INF/grails-app/i18n/messages"
}
}
In the gsp page g:message is called as shown below
1.<g:message code="someObject.create"/>
2.<g:message code="someObject.create" default="Create"/>
3.<g:message code="someObject.create" args="['']"/>
For the same code given in the g:message tag, 1,2 is not displaying the text given in the database. The 3rd tag usage is showing the text content added in the database. 1 tag is showing the someObject.create. 2 Tag is showing Create value, 3rd tag shows the db text added.
why 1 and 2 notations are not displaying the dynamic value in the database? and also that the resolveCode() is called for 1Time only.

How to make my audit trail plugin work

I am in an need to use audit trail in my grails application i have tried all methods but audit log is empty is there any way to rectify it.I need to actually record operations such as insert,delete and update.
Below is what I followed:-
package audit
class Person {
static auditable = true
String firstName
static constraints = {
firstName(nullable:true,size:0..60)
}
def onSave = {
println "new person inserted"
}
def onUpdate = {
println "person was updated"
}
def onDelete = {
println "person was deleted"
}
def onChange = { oldMap,newMap ->
println "Person was changed ..."
oldMap.each{ key, oldVal ->
if(oldVal != newMap[key]) {
println " * $key changed from $oldVal to " + newMap[key]
}
}
}
}
Other listservs that I check have suggested that the current audit-logging plugin is buggy, so you may just be experiencing a bug in the plugin. Also, I believe it has been forked and is actively being rewritten (http://jira.grails.org/browse/GPAUDITLOGGING), so you may not want to spend too much time with it right now.
With that said, I scaffolded a simple application with the domain you provided and the plugin did write out the println statements, but it only recorded the updates correctly in the database to the AUDIT_LOG table. The 2 inserts I attempted recorded null for both the NEW_VALUE and PROPERTY_NAME.

Writing an Integration Test in Grails that will test DB persistence

My Integration-Test for my grails application is returning a null object when I try to get a domain object using grails dynamic get method.
This is a simplified example of my problem. Lets say I have a controller TrackerLogController that uses a service TrackerLogService to save an updated Log domain for another Tracker domain.
Domain Tracker:
class Tracker {
int id
String name
static hasMany = [logs: Log]
}
Domain Log:
class Log {
int id
String comment
static belongsTo = [tracker: Tracker]
}
Controller TrackerLogController save:
def TrackerLogService
def saveTrackerLog() {
def trackerId = params.trackerId
def trackerInstance = Tracker.get(trackerId)
Log log = TrackerLogService.saveTrackerLogs(trackerInstance, params.comment)
if( log.hasErrors() ){
//render error page
}
//render good page
}
Service TrackerLogService save:
Log saveTrackerLogs( Tracker tracker, String comment) {
Log log = new Log(tracker: tracker, comment: comment)
log.save()
return log
}
So now I want to write an Integration-Test for this service but I'm not sure if I should be writing one just for the simple logic in the controller (if error, error page else good page) I would think I would write a Unit test for that, and an Integration-Test to check the persistence in the Database.
This is what I have for my Integration-Test:
class TrackerLogServiceTests {
def trackerLogService
#Before
void setUp(){
def tracker = new Tracker(id: 123, name: "First")
tracker.save()
//Now even if I call Tracker.get(123) it will return a null value...
}
#Test
void testTrackerLogService() {
Tacker trackerInstance = Tracker.get(123) //I have tried findById as well
String commit = "This is a commit"
//call the service
Log log = trackerLogService.saveTrackerLogs(trackerInstance , commit)
//want to make sure I added the log to the tracker Instance
assertEquals log , trackerInstance.logs.findByCommit(commit)
}
}
So for this example my trackerInstance would be a null object. I know the Grails magic doesn't seem to work for Unit tests without Mocking, I thought for Intigration-Tests for persistence in the DB you would be able to use that grails magic.
You can't specify the id value unless you declare that it's "assigned". As it is now it's using an auto-increment, so your 123 value isn't used. It's actually ignored by the map constructor for security reasons, so you'd need to do this:
def tracker = new Tracker(name: "First")
tracker.id = 123
but then it would get overwritten by the auto-increment lookup. Use this approach instead:
class TrackerLogServiceTests {
def trackerLogService
private trackerId
#Before
void setUp(){
def tracker = new Tracker(name: "First")
tracker.save()
trackerId = tracker.id
}
#Test
void testTrackerLogService() {
Tacker trackerInstance = Tracker.get(trackerId)
String commit = "This is a commit"
//call the service
Log log = trackerLogService.saveTrackerLogs(trackerInstance , commit)
//want to make sure I added the log to the tracker Instance
assertEquals log , trackerInstance.logs.findByCommit(commit)
}
}
Also, unrelated - don't declare the id field unless it's a nonstandard type, e.g. a String. Grails adds that for you, along with the version field. All you need is
class Tracker {
String name
static hasMany = [logs: Log]
}
and
class Log {
String comment
static belongsTo = [tracker: Tracker]
}

Domain class hasMany fails to add entry

I'm a Grails noob so please excuse my noob question.
I've created a domain classes User and Device. User hasMany devices:Device, and Device belongsTo user:User.
It is important that only 1 device will never belong to two users so my UserController code looks like this:
class UserController {
static allowedMethods = [create: 'POST']
def index() { }
def create() {
def user = User.findByUsername(request.JSON?.username)
def device = Device.findById(request.JSON?.deviceId)
if (device) {
device.user.devices.remove(device)
}
// device can only be owned by 1 person
def new_device = new Device(id: request.JSON?.deviceId, type: request.JSON?.deviceType)
if ( !user ) {
user = new User(
username: request.JSON?.username
)
user.devices = new HashSet() // without this I get null on the add in next line
user.devices.add(new_device)
user.save()
if(user.hasErrors()){
println user.errors
}
render "user.create " + request.JSON?.username + " devices.size " + user.devices.size()
} else {
user.devices.add( new_device )
user.save()
if(user.hasErrors()){
println user.errors
}
render "user.create exists, new token: " + user.token + " devices.size " + user.devices.size()
}
}
}
But now I get a strange server error:
null id in Device entry (don't flush the Session after an exception occurs)
What am I missing here??
Thanks a lot!
First of all, there are special methods to add to and remove from. Do not operate straight on hasMany collections. Maybe this is problematic.

Resources