not able to edit currently logged-in user profile in Grails - grails

I am trying to edit currently logged-in user profile. I have used Spring Security Service plugin for user management. User ( which is subscriber in my application) contains field which come from different domain like:
1. User(subscriber in app): has username, password.
2 Profile:has emailaddress and phonenumber etc.
3. Person:has Firstname and lastname.
All above domains make a complete profile for user(subscriber).
Now I want to edit currently logged-in user profile like firstname, lastname or email.
I tried with following code.
def userSettings = {
Subscriber loggedinSubscriber = Subscriber.get( springSecurityService.principal.id )
if (loggedinSubscriber){
Profile profile = Profile?.get(params.id);
Party person = profile?.Person?.get(params.id);
if (!person){
flash.message = "could not find user with ${params.id}"
redirect action: list
}
else
[person: person, authorityList: sortedRoles()]
}
else {
redirect(controller: "login" , action:"login");
}
}
But it did not work. Here I got currently logged in user id but profile is null.
Profile domain:
package com.vproc.member
import java.util.Date;
import com.vproc.enquiry.Enquiry;
import com.vproc.enquiry.Membership;
import com.vproc.enquiry.Team;
class Profile {
String emailAddress // field governed by privacy policy
String phoneNumber // field governed by privacy policy
Date dateCreated
Date lastUpdated
boolean isDefaultProfile
static belongsTo = [ Person]
//ProfilePrivacyLevelEnum privacyLevel = ProfilePrivacyLevelEnum.Private
static constraints = {
}
}
Person domain:
package com.vproc.member
import com.vproc.enquiry.Enquiry;
import com.vproc.enquiry.Membership;
import com.vproc.enquiry.Notification;
import com.vproc.enquiry.Team;
class Person extends Party{
String firstName
String lastName
Profile profile
static belongsTo = [Organization]
static constraints = {
lastName nullable:true
firstName blank:false
}
}
Subscriber domain:
package com.vproc.member
import java.util.Date;
import com.vproc.common.StatusEnum;
import com.vproc.enquiry.Discussion;
import com.vproc.enquiry.Enquiry;
import com.vproc.enquiry.Membership;
import com.vproc.enquiry.Notification;
import com.vproc.enquiry.SharedEnquiry;
import com.vproc.enquiry.Team;
import com.vproc.order.Seat;
class Subscriber extends PartyRole{
transient springSecurityService
String username
String password
boolean enabled
boolean accountExpired
boolean accountLocked
boolean passwordExpired
StatusEnum status
Date dateCreated
Date lastUpdated
List<Contact> contacts ;
static belongsTo = [ customer: Customer]
static hasMany = [seats: Seat, ownedEnquiries: Enquiry,enquiresSharedWith: SharedEnquiry,]
static constraints = {
// username validator : { val , obj ->
// if (obj.status != StatusEnum.Pending)
// val!= null
// }
username unique: true
password validator : { val , obj ->
if (obj.status != StatusEnum.Pending)
val != null
}
contacts nullable: true
notifications nullable : true
username nullable: true
password nullable: true
}
}
UserController.groovy
package com.vproc.member
import com.vproc.common.StatusEnum
import com.vproc.exception.CustomValidationException;
class UserController extends AbstractS2UiController {
def saltSource
def userCache
def springSecurityService
def mailService
def messageSource
def create = {
//Subscriber user = lookupUserClass().newInstance(params)
UserCommand command = new UserCommand()
[command: command, authorityList: sortedRoles()]
}
def save = { UserCommand command ->
if (command.hasErrors()) {
render view: 'create', model: [command: command]
return
}
Subscriber user = lookupUserClass().newInstance(params)
Profile profile = new Profile(emailAddress : command.emailAddress, phoneNumber: "234555", isDefaultProfile: "true").save()
Party person = new Person(firstName: command.firstName, lastName: command.lastName, profile: profile).save()
user.party = person
if(! user.party.hasErrors()){
if (params.password) {
String salt = saltSource instanceof NullSaltSource ? null : params.username
user.password = springSecurityUiService.encodePassword(params.password, salt)
user.status = StatusEnum.Active
}else{
user.status = StatusEnum.Pending
}
Subscriber loggedinSubscriber = Subscriber.get( springSecurityService.principal.id )
user.customer = loggedinSubscriber.customer
if (!user.save(flush: true)) {
flash.message = "not able to save user"
}
}
else{
flash.message = "not able to save user"
}
//addRoles(user)
//flash.message = "User has been added"
flash.message = "${message(code: 'default.created.message', args: [message(code: 'user.label', default: 'User'), user.id])}"
redirect( action : "list" )
}
def edit = {
String username
def user = params.username ? lookupUserClass().findWhere((usernameFieldName): params.username) : null
if (!user) user = findById()
if (!user) return
return buildUserModel(user)
}
// def contacts = Contact.findAllBySubscriber( loggedinSubscriber)
def userSettings = {
Subscriber loggedinSubscriber = Subscriber.get( springSecurityService.principal.id )
if (loggedinSubscriber){
Profile profile = Profile?.get(params.id);
Party person = profile?.Person?.get(params.id);
if (!person){
flash.message = "could not find user with ${params.id}"
redirect action: list
}
else
[person: person, authorityList: sortedRoles()]
}
else {
redirect(controller: "login" , action:"login");
}
}
}
Now I want to edit profile of currently logged-in user using method userSettings in usercontroller. I got id of currently logged in user id but I am not able to use that id with profile and person.
Subscriber loggedinSubscriber = Subscriber.get( springSecurityService.principal.id )
if (loggedinSubscriber){
Profile profile = Profile?.get(params.id);
Party person = profile?.Person?.get(params.id);
Using above code, profile value is null.

Ok I dont't want to understand all of your domain modeling, so I'm answering on the thing that I noticed right after having a look at your code. I hope it helps, otherwise just use debug and logging a lot to tackle down your error. And read the documentation.
First of all, in Profile.groovy (and other Domains) use a map to define belongsTo:
static belongsTo = [person:Person]
that also does not look right:
Profile profile = Profile?.get(params.id);
When you have a static access to a grovvy class (upper case first letter) you don't need the questionmark. Is params.id supposed to be the ID of the profile? Then you need to use the findBy methods:
Profile profile = Profile.findById(params.id);
Then in the next line you have to use the key from your belongsTo map again, so person instead of Person:
// no get or findBy required
Party person = profile?.person
Hope it helps

I got solution with following code:
def userSettings = {
Subscriber loggedinSubscriber = Subscriber.get( springSecurityService.principal.id )
Party person = Person?.get(loggedinSubscriber.party.id)
Profile profile = person?.profile
[userInstance: profile, authorityList: sortedRoles()]
}
Thanks BurtBeckwith and moeTi.

Related

Grails one to many relationship Error

I have a User domain Class as follows:
package xyz
class User {
String login
String password
String firstName
String lastName
String address
String email
static hasMany = [
websites: AddWebsite
]
static constraints = {
login blank:false, size:5..15,matches:/[\S]+/, unique:true
password blank:false, size:5..15,matches:/[\S]+/
firstName blank:false
lastName blank:false
email email: true
}
}
and another AddWebsite domain class as follows:
package xyz
import xyz.User;
class AddWebsite {
String website
User user
static belongsTo = [user: User]
static constraints = { website url:true }
}
I am working with MongoDB at the backend. I need that every user who logs in can add websites but a user can't add same websites multiple times but same website can be added by different users. Whenever I try to add a website, it shows me "user cannot be null error".
My controller class for AddWebsite is as follows:
package xyz
class AddWebsiteController {
def index() {
}
def addWebsites() {
if(request.method == 'POST') {
def u = new AddWebsite()
u.properties[
'website'
] = params
if(u.website =="" ) {
u.errors.rejectValue("website", "addwebsite.website.empty")
return [addWebsite:u]
}
else if(u.save()) {
render view:'addWebsites', model:[message: "Successfully saved: \""+u.website+"\" Add more websites..."]
//redirect(controller: "AddWebsite", action: "websiteAdded")
}
else {
return [addWebsite:u]
}
}
}
def websiteAdded() {
}
def failed(){
}
}
Also, I am not sure how to test whether this one to many association. Please help.
Figured it out. I made this change in the controller so that the user won't be null anymore:
def addWebsites() {
if(request.method == 'POST') {
def w = new AddWebsite()
w.properties[
'website'
] = params
w.user = session["user"] //modified
if(w.website =="" ) {
w.errors.rejectValue("website", "addwebsite.website.empty")
return [addWebsite:w]
}
else if(w.save()) {
render view:'addWebsites', model:[message: "Successfully saved: \""+w.website+"\" Add more websites..."]
}
else {
return [addWebsite:w]
}
}
}

Grails clear hasMany entries and add new ones error?

I am currently working on a grails applications and I have a list of addresses that are attached to an account. Basically what I want to do is when the Account is edited is displays a current list of all the attached Addresses and then I can delete/add as many as I want from the view. When this data is captured it is picked up by the controller and what I want to do is to be able to clear all of the current Addresses from this account and then create the list again with what exists on the view, my code is below:
Account Domain:
class Account {
String name
Date dateCreated
Date lastUpdated
static hasMany = [addresses:Addresses]
static mapping = {
addresses cascade:"all-delete-orphan"
}
def getAddressesList() {
return LazyList.decorate(
addresses,
FactoryUtils.instantiateFactory(Addresses.class))
}
static constraints = {
name(blank:false, unique: true)
}
}
Address Domain:
class Addresses {
int indexVal
String firstLine
String postcode
String area
static belongsTo = [account:Account]
static mapping = {
}
static transients = [ 'deleted' ]
static constraints = {
indexVal(blank:false, min:0)
}
}
Account Controller:
def update() {
def accountInstance = Account.get(params.id)
if (!accountInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'account.label', default: 'Account'), params.id])
redirect(action: "list")
return
}
if (params.version) {
def version = params.version.toLong()
if (accountInstance.version > version) {
accountInstance.errors.rejectValue("version", "default.optimistic.locking.failure",
[message(code: 'subscriptions.label', default: 'Subscriptions')] as Object[],
"Another user has updated this Account while you were editing")
render(view: "edit", model: [accountInstance: accountInstance])
return
}
}
accountInstance.properties = params
accountInstance.addresses.clear()
accountInstance.save(flush: true)
....
}
Error:
A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: com.tool.Account.addresses. Stacktrace follows:
Message: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: com.tool.Account.addresses
This error seems to be occurring in the controller on line:
accountInstance.save(flush: true)
I have tried several different way to get this to work and would really appreciate some help.
So it seems like you have done some work that Grails can do for you.
class Account {
String name
Date dateCreated
Date lastUpdated
List addresses
static hasMany = [addresses:Address]
static mapping = {
addresses cascade:"all-delete-orphan"
}
static constraints = {
name(blank:false, unique: true)
}
}
class Address {
String firstLine
String postcode
String area
static belongsTo = [account:Account]
}
This will produce the effect you want of having addresses being a list.
I've found either
instance.addresses = null
or
instance.addresses.clear()
to work for me
When you define addresses cascade:"all-delete-orphan" in Account class you don't need static belongsTo = [account:Account] in Addresses. So just try to remove that statement and test your code. See related link.

Grails 2.1 Join Query

I m new user in Grails. I don't know how to write projection query. Here is my code. please anyone help me for grails projection query.
From Join table I want to find username which is consist in user table
Given the following example domains:
class User{
transient springSecurityService
String username
String password
boolean enabled
boolean accountExpired
boolean accountLocked
boolean passwordExpired
static mapping = {
table 't04t001'
id column: 'f_account_id'
username column: 'f_username', length: 10
password column: 'f_password', length: 100
enabled column: 'f_account_active'
accountExpired column: 'f_account_expired'
accountLocked column: 'f_account_locked'
passwordExpired column: 'f_password_expired'
version column: 'f_revision'
}
}
class Role{
String role
static mapping = {
table 't04t003'
id column : 'f_role_id'
role column : 'f_role'
version column : 'f_revision'
cache true
}
}
class UserRole implements Serializable {
User user
Role role
static mapping = {
table 't04j002'
id composite : ['role', 'user']
role column :'k_role_id'
user column :'k_user_id'
version false
}
}
I can't figure out how to build the criteria to find all the user. I tried the following:
def criteria = UserRole.createCriteria()
def list = criteria.list {
projections {
user{
ilike('username', 'omar')
}
}
}
In console mode i have seen this query with message
Hibernate:
select
this_.k_role_id as k1_3406_0_,
this_.k_user_id as k2_3406_0_
from
t04j002 this_
where
(
lower(user_alias1_.f_username) like ?
)
However, it says Unknown column 'user_alias1_.f_username' in 'where clause'.
But i cant figure out this(user_alias1_) alias
I am not exactly clear on what you want to retrieve from which table. So based on your criteria query, here is how to retrieve user from the UserRole table.
def criteria = UserRole.createCriteria()
def result = criteria.list {
projections {
property("user")
}
user {
eq("username", "omar") //strict match
}
}
return result;
What this does is it builds a list that has the user.username as omar. By default the result will be the UserRole object, but to get user object instead we used projections.
Update:
Your Domain class seems a bit out of grails conventions. Why not user something like this?
//User.groovy
class User {
String username
// ..
static constraints = {
username blank: false, nullable: false, maxSize: 10
}
}
//UserRole.groovy
// Since you are using composite keys, we have to implement serializable. But is there a need for composite key in your situtation?
class UserRole implements Serializable {
User user
// ..
}
In you service class
// UserRoleService.groovy
def getUser(String username) {
def criteria = UserRole.createCriteria()
def result = criteria.get {
projections {
property("user")
}
user {
ilike("username", username)
}
}
return result;
}
And to call the service method from controller,
// ExampleController.groovy
class ExampleController {
def userRoleService
def index() {}
def someThing(String username) {
def user = userRoleService.getUser(username)
println user?.username
// ..
}
}

How to save associated object in Grails?

I am a grails beginner.
i have a 2domain class
class Employee {
String name
String department
static constraints = {
}
public String toString() {
name
}
}
class Address {
String line1
String line2
Employee employee
static belongsTo = Employee
static constraints = {
}
}
where Address belongs to Employee .. so i have given belongsTo association.
My Employee/create.gsp page takes input for fields specified in Employee and Address.
so on creation of employee , address must be get save automatically .
so what could be the save action in EmployeeController
i have tried some thing like this but did not work.
def save = {
def employeeInstance = new Employee(params)
def addressInstance = new Address(params)
if (employeeInstance.save(flush: true)) {
flash.message = "${message(code: 'default.created.message', args: [message(code: 'employee.label', default: 'Employee'), employeeInstance.id])}"
redirect(action: "show", id: employeeInstance.id)
}
else {
render(view: "create", model: [employeeInstance: employeeInstance])
}
}
how to save this associated model ?
Here you have a one-to-one relationsip - add an address property to the Employee class.
class Employee {
String name
String department
Address address
public String toString() {
name
}
}
Change your belongsTo of the Address like this:
class Address {
String line1
String line2
static belongsTo = [employee: Employee]
}
Now you could create an Employee like this:
def employeeInstance = new Employee(params)
employeeInstance.address = new Address(params)
if (employeeInstance.save(flush: true)) {
// your logic
}
Read the docs (one-to-one relationship) for further informations.

Grails Integration test: Failure...Cannot invoke method addToPosts() on null object

:D
I was following a tutorial in a book, and I did follow it thoroughly.
However, come the part where I am supposed to write an integration test, it suddenly failed saying: Cannot invoke method addToPosts() on null object right after I ran the test. I wonder, what could be wrong... :| Please help! :) Below is the code for the test:
void testFirstPost() {
def user = new User(userID: 'joemillan', password:'youaretheonly',
homepage: 'www.geeee.com').save()
def post = new Post (content: 'hellloo oasdo sjdosa daodkao ')
user.addToPosts(post)
assertEquals 1, User.get(user.id).posts.size()
}
Here is the user class:
class User {
String userID
String password
String homepage
Profile profile
static hasMany=[posts:Post, tags:Tag]
static constraints = {
userID (unique: true, size: 6..20)
password (size: 6..20, validator:{password,userID-> return password !=userID.userID}) //validator = The password must not match the username.
homepage (url:true, nullable: true)
profile (nullable: true)
}
}
Here is the Post class:
class Post {
String content
Date dateCreated
static constraints = {
content (blank:false)
}
static belongsTo = [user:User]
static hasMany = [tags:Tag]
static mapping = {
sort dateCreated: "desc"
}
}
save() returns null if validation fails, and "www.geeee.com" isn't a valid URL. It would work with "http://www.geeee.com".
But you should split the creation and saving into 2 steps so you can check it:
def user = new User(userID: 'joemillan', password:'youaretheonly',
homepage: 'www.geeee.com')
user.save()
assertFalse user.hasErrors()
or use failOnError if you are confident that that part should succeed and only want to test the other parts, e.g.
def user = new User(userID: 'joemillan', password:'youaretheonly',
homepage: 'www.geeee.com').save(failOnError: true)

Resources