Grails find by property - grails

Okay, I am trying to find all of my Employee that have a given role... However no matter what I try I end up getting the same exception thrown...
enum Role {
SFC("State Fitness Coordinator"),
TRAINING("Training"),
DFC("District Fitness Coordinator"),
final String longName
private Role(String longName) {
this.longName = longName
}
}
class Employee {
static hasMany = [roles: Role]
static constraints = {
}
}
The first Thing I tried was Employee.findAllByRoles(Role.DFC)
Then I tried:
Employee.findAll("FROM Employee e WHERE e.roles IN (:role)", [role: [Role.DFC]])
as well as
Employee.withCriteria {
'in'('roles', [Role.DFC])
}
all resulting in
Class
java.sql.SQLException
Message
Missing IN or OUT parameter at index:: 1
Any direction would be much appreciated.

with grails 2.3.8 and H2
Employee.findAll("FROM Employee e WHERE :role in elements(e.roles) ", [role: Role.DFC.toString()])
this works… even if I think that Role could be a real Domain simplifying all operations

I think the problem is that Role is an enum. Are you sure you want to make it an enum?
I recommend making it a class since new roles might be added. If so, you can easily add a record using bootstrap or SQL query without making a new build to production.
class Role {
String roleName
String description
}
In Bootstrap:
Role sfc = new Role("SFC","State Fitness Coordinator")
Role sfc = new Role("TRAINING," "Training")
Role sfc = new Role("DFC", "District Fitness Coordinator")
N.B. Please make sure you are not using spring security plugin which has its own 'Role' class. If so, please change the name of your 'Role' class to something like 'EmployeeRole'

Related

Unit test Custom authorize attribute

I've written a custom claims authorizatize attribute and I would like to unit test the code I've written but have been unable to find what I'm looking for on SO.
For example, this is my custom authorize attribute class:
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using IPD2.MVC.Interfaces.Providers;
using IPD2.MVC.Providers;
namespace IPD2.MVC.Attribute
{
public class ClaimsAuthorizeAttribute : AuthorizeAttribute
{
private readonly string _claimValue;
private readonly string _claimType;
private readonly ITokenProvider _tokenProvider;
public ClaimsAuthorizeAttribute(string type, string value)
{
_claimType = type;
_claimValue = value;
_tokenProvider = new TokenProvider();
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
var jwt = _tokenProvider.ApiToken as JwtSecurityToken;
if (jwt == null)
{
HandleUnauthorizedRequest(filterContext);
}
else
{
var claim = jwt.Claims.FirstOrDefault(expr => expr.Value == _claimValue);
var authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
var formsAuthenticationTicket = FormsAuthentication.Decrypt(authCookie.Value);
if (formsAuthenticationTicket != null && !formsAuthenticationTicket.Expired)
{
var roles = formsAuthenticationTicket.UserData.Split(',');
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new FormsIdentity(formsAuthenticationTicket), roles);
}
}
if (claim != null)
{
base.OnAuthorization(filterContext);
}
else
{
HandleUnauthorizedRequest(filterContext);
}
}
}
}
}
Test code
public class GivenCallingClaimAuthorizationAttribute : SpecsFor<ClaimsAuthorizeAttribute>
{
//HttpActionContext actionContext;
//IPrincipal originalPrincipal;
protected override void Given()
{
SUT = new ClaimsAuthorizeAttribute(ClaimTypes.Role, "ImNotAllowedToUseController :(");
}
public class WhenUserIsNotAllowedToAccessController : GivenCallingClaimAuthorizationAttribute
{
protected override void When()
{
SUT.OnAuthorization(
new AuthorizationContext()
);
}
}
[Test]
public void ThenAssertSomethingBasedOnCodeInTest()
{
//todo: some assert
}
}
I've written this basic test class with the SpecsFor BDD framework but I'm not sure what it needs to test it succesfully.
Any ideas on how to test this? As you can see, I'm testing the class itself rather than a controller with the attribute. I'm not sure about a good way to test this.
If you want to do BDD, think about the behaviour of your class. What kind of things should it be able to do?
For instance, perhaps it should:
- authorize current users
- filter users whose ticket has expired
- assign authorized users with the correct roles
- etc.
Let's say we're going to look at the second one of those, because it's interesting. I'll ask you, "Can you give me an example of when a ticket might expire?"
And you say, "Yes, the timeout is 500ms so anything older than that is expired." Or you say, "These are tickets to a football match and are given out yearly." (I don't know what a ticket is, but this conversation would help me work that out.)
So then we can write an example:
Given we've got a handler for unauthorized tickets
Given Fred's ticket expired on 2017-05-14
And it's now 2017-05-14
When we try to authenticate Fred
Then Fred should not be authenticated
And the handler should be given Fred's details
Next I like to put these in comments in code, with the "should" as the title of the test. After that, it's just a matter of setting up the context (in the Given), passing it to your code to exercise (the When) and verifying the outcome (the Then).
However, you can see that your Specs framework only allows for one given! That's not great, since I've already identified several scenarios which require different contexts. If you use SpecsFor the way you're using it, you'll have to make one class for each of my scenarios, and they won't be very easy to read!
I highly recommend using the second style instead, and start just with the Given, When, Then in comments.
The thing is, unit tests' steps aren't really reused much, compared to say a full-system BDD scenario, in which contexts are often called several times for different capabilities. A unit of code (or class) tends to fulfil one responsibility, or it gets refactored that way, and its contexts don't bleed into other classes because Mocks.
So, I find that just having Given, When and Then in comments is enough.
I therefore recommend you switch to the "old school" way of doing things that I can see in this page (down the bottom) and just start with the comments. See how that goes for you.
By the way, if you really want to do BDD properly, then you want to drive the development with the examples of how it behaves, and incrementally fill in the code to make those examples work, rather than writing them down. The book "Growing Object Oriented Software, Guided By Tests" will be very helpful for you.

Grails Elasticsearch plugin issues

I am new to Elasticsearch and am using the revived grails plugin "elasticsearch:0.0.4.6".
I wanted to implement a search for a User by their firstName, surname or username, which returns the full domain instance.
I have a 2 domain classes:
User:
class User {
String firstName
String surname
static hasOne = [profile:Profile]
static hasMany = [friends:User]
static mappedBy = [ friends: 'friends' ]
static searchable = {
profile component:true
only = ['firstName', 'surname', 'profile']
}
...
Profile:
class Profile {
String username
String status
byte[] photo
static belongsTo = [user:User]
static searchable = true
...
}
I made the classes "searchable = true" and then created the following search:
def res = User.search("${params.friendSearch}").searchResults
This found the correct instances, but now when a user adds a photo to their profile, it suceeds but I recieve a never ending loop of the following error:
ERROR index.IndexRequestQueue - Failed bulk item: MapperParsingException[failed to parse [photo]]; nested: NumberFor
matException[For input string: the photos base64inputstring
I dont really get what is happening, but i figure it must be something to do with elasticsearch being unable to index the photo data. Can somebody provide an explanation?
I then experimented with searchables custom mapping options -
profile index:'no'
all=false
excludeFromAll = true
etc
Nothing worked. Eventually I added
only = ['username']
and it stopped the error from occuring and allowed me to find users based on the criteria i mentioned above. However, because of the "only" limit, it means that the User instances returned by the seach have a photo property equal to null, but i need this value!
What am i doing wrong? Can anyone advise me on the best course of action to take or any misunderstandings i have about Elasticsearch? Thanks
I think you might have to exclude the byte property photo from the searchable fields like so:
class Profile {
String username
String status
byte[] photo
static belongsTo = [user:User]
static searchable = {
except = ['photo']
}
This will exclude the property photo from being indexed and search. Hence the output of converting the byte format to string format will not fail.
Also maybe you might need a custom convertor to change the byte(string) to something more usable in the results?

Grails loading data once

I have these 2 domains
class Country {
String name
static hasMany = [cities:City]
}
class City {
String name;
static belongsTo = [country: Country]
}
The data contained in these 2 tables is relatively big, and they're used in all the screens,
every time i choose a country i have to reload all its cities.
How can I load the data only once in memory so i can access it faster in all the screens.
I tried putting cities for eager fetching, and tried using cache plugin.
Thank you
You can configure both domain classes to be cached automatically and also cache the cities relation in Country:
class Country {
String name
static hasMany = [cities:City]
static mapping = {
cache true
cities cache:true
}
}
class City {
String name
static belongsTo = [country: Country]
static mapping = {
cache true
}
}
Caching is often a good strategy, but remember that caches have expiry parameters so if left idle your app may reload from the DB again. Depending on your cache provider you'll have to tune this, eg For ehcache edit your ehcache.xml in the grails config folder and set (cache name is the same as your Domain class including package name):
<cache name="Country" maxElementsInMemory="1000" timeToIdleSeconds="0" timeToLiveSeconds="0"/>
You should also move the query into a service, the service is by default singleton scoped and the service method also cachable.
An alternative is to store them in application scope such as in your Bootstrap.groovy run the query and assign the results:
servletContext.countries = Country.list()
Retrieve them in the same way, eg
in a controller:
List<Country> countries = servletContext.countries
or gsp:
<g:each var="country" in="${application.countries}">
${country}
</g:each>
If you have eager fetching on then you should see no DB hits.

Unable to create new domain object in Grails

Hi there i am still very new to grails and I have not been able to figure out why this is happening.
I have a domain class:
package scheduler
class Client {
String name
static constraints = {}
}
And a controller:
package scheduler
class AdminController {
def create() {
def client = new Client(name:"John")
println client
}
}
Currently I am always getting null for client. Originally the above was a little more complex on the domain class side but I systematically dumbed it down to see if it was a problem there. I still can not get the above working.
The output is always
scheduler.Client : null
Please let me know if I need to provide anymore information.
It's not null, that's just the default output of the toString method that Grails adds. It prints the class name and the id. Since you haven't saved the instance, the id is null. If the instance was null the output would have been null, not scheduler.Client : null
If you want to see the data in the instance, use the Groovy dump() method, e.g.
def client = new Client(name:"John")
println client.dump()
You could also add a toString method that includes the name attribute, e.g.
package scheduler
class Client {
String name
String toString() { name }
}

How Do I Decide My Domain Model In This Case?

I need to develop a application for a user's management in a IT Project. This is done in order to learn Grails. I have some problem to start with :
In my sample app, a user has many tasks, belongs to a project, have many holiday status, belongs to the Resource planning and thats it. (kind of requirements!)
Now..... When it comes to domain modeling, how I actually model this? I came up the solution of modeling something like this :
class User {
//relationships. . . .
static belongsTo = [ company : Company, role : Role, resource : Resource]
static hasMany = [ holidays : Holiday, tasks : Tasks ]
Profile profile
Project project
String login
String password
static constraints = {
login(unique:true,size:6..15)
profile(nullable:true)
}
String toString() {
this.login
}
}
Now taking advantage of Grails scaffolding. I generated the view, hmmm well thats where I got struck!
With this model in place, clearly when creating a new User., I need to give away project details, resource details. Even though I can change the view as I need, for example I need only two fields say login and password for the new User to register my site. But as per data modeling, how I can handle other fields like Profile, Project and other relationships. This sounds complicated! I know i'm a newbie to both web development and I want your suggestions and how do I proceed with this?
Thanks in advance.
You need to override the save action in your controller and fill those additional fields there.
Try adding the following code in UserController:
def save = {
def userInstance = User.get(params.id)
if (!userInstance) {
userInstance = new User()
// here you can fill in additional fields:
userInstance.profile = myMethodToGetTheProfile()
userInstance.project = myMethodToGetTheProject()
...
}
userInstance.properties = params
if (userInstance.save(flush: true)) {
flash.message = message(code: 'default.created.message', args: [message(code: 'User.propertyName.label', default: 'User'), userInstance.id])}
redirect(action: session.lastActionName ?: "list", controller: session.lastControllerName ?: controllerName)
} else {
render(view: "form", model: [userInstance: userInstance, mode: 'edit'])
}
}
The implementation of methods to get the default project depends on your app's logic.

Resources