0

I am working on a JHipster application, I have a Study entity which has a many-to-one relationship with User (So one user can have many studies). I am trying to change the user select in the dialog component for creating a new Study to automatically select the current logged in user.

I have changed the select so that only the single user should show up as an option for the select, after fixing this issue I would either disable the field or remove it so that study.user is automatically set:

<select class="form-control" id="field_user" name="user [(ngModel)]="study.user" > 
    <option [ngValue]="user.id === study.user?.id ? study.user : user">{{user.login}}</option> 
</select>

The userService is queried though:

this.userService.query() 
    .subscribe((res: ResponseWrapper) => { this.user = res.json; }, (res: ResponseWrapper) => this.onError(res.json)); 

Which runs this query to the api in user.service.ts:

private resourceUrl = 'api/users';
...
query(req?: any): Observable<ResponseWrapper> {
    const options = createRequestOption(req);
    return this.http.get(this.resourceUrl, options)
        .map((res: Response) => this.convertResponse(res));
}

The GET method in UserResource.java:

@GetMapping("/users")
@Timed
public ResponseEntity<UserDTO> getAllUsers() {
    return ResponseUtil.wrapOrNotFound(
        userService.getAllManagedUsers()
            .map(UserDTO::new));
}

Which calls this method in UserService.java:

@Transactional(readOnly = true)
public Optional<User> getAllManagedUsers() {
    return userRepository.findOneByLogin(SecurityUtils.getCurrentUserLogin());
}

findOneByLogin is defined in userRepository, the Spring Data JPA repository for the User entity.

My issue is that when I try to access the user object from my entity, it is undefined, throwing errors such as:

ERROR TypeError: Cannot read property 'id' of undefined

fralewsmi
  • 92
  • 2
  • 12

2 Answers2

5

If I understood correctly, you have a Study which has a relationship with User and when you retrieve a Study object: study.user is undefined in your problem in angular code.

You can't trust angular code, so User selection cannot be in client when creating a Study, so you should ignore it in StudyMapper (assuming you use DTOs) or StudyService should overwrite it.

JHipster creates views and APIs that are for administrators. In your case you want to build an API for simple users who are only allowed to manage their own studies, if you try to address both use cases in same classes your code could get messy and you may introduce security flaws. So I'd suggest that you split the 2 APIs and probably views unless you want to drop the admin part. By having StudyResource on/api/study for admins and MyStudyResource on /api/user/study, you can protect them differently by role and avoid the issues you have in view because you'll have a well-defined context rather than putting if/then/else all a round.

Another reason to do so is that it makes easier to upgrade JHipster generated code using jhipster upgradecommand.

JHipster does not design your API because it does know about your business domain. It provides you with a CRUD interface to manage data above a REST API and entities from a technical standpoint. This is why it maps one resource per entity rather than aggregates which are what you end up with when you analyze your business domain using DDD. Aggregates are better also in terms of performance especially for mobile clients because you end up making less API calls.

You could also add an API using https://github.com/cbornet/generator-jhipster-swagger-api-first

Gaël Marziou
  • 16,028
  • 4
  • 38
  • 49
  • I have updated my question to clarify the relationship with User. This is an issue with the creation of a new Study, where in the study-dialog component there is a select for choosing the User related to the study. I am trying to change this so that only the current logged on user is retrieved, instead of all users in the application – fralewsmi Aug 19 '17 at 10:02
  • Thankyou, something to think about for my API design – fralewsmi Aug 19 '17 at 12:04
  • 1
    Absolutely, JHipster is an awesome tool but it is just a technical tool with no business insights. – Gaël Marziou Aug 19 '17 at 13:28
2

I did something similar: In xxxResource.java:

 public String getCurrentUserLogin() {
        org.springframework.security.core.context.SecurityContext securityContext = SecurityContextHolder.getContext();
        Authentication authentication = securityContext.getAuthentication();
        String login = null;
        if (authentication != null)
            if (authentication.getPrincipal() instanceof UserDetails)
             login = ((UserDetails) authentication.getPrincipal()).getUsername();
            else if (authentication.getPrincipal() instanceof String)
             login = (String) authentication.getPrincipal();

        return login; 
        }

then before xxxRepository.save add:

 User user=new User();
 user=UserRepository.findOneByLogin(getCurrentUserLogin()).get();
 Order.setUser(user);

See https://codefitter2.blogspot.com/2016/12/how-to-add-user-to-new-record-in.html

Nico
  • 505
  • 4
  • 14
  • Thanks Nico! This solved my problem which I've had for about 2 weeks now. Although Gael has a strong point in suggesting I follow an API-first design, this removed my dependency on having a user selection. I used `study.setUser` instead of `Study.setUser` (where order is the name of my entity) and according to my IDE `User user=new User()`; is a redundant statement (I'm not gonna bother removing it though). – fralewsmi Aug 29 '17 at 10:58