Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
package com.ippon.belt.web.rest;
import com.ippon.belt.config.Constants;
import com.ippon.belt.domain.User;
import com.ippon.belt.repository.UserRepository;
import com.ippon.belt.security.AuthoritiesConstants;
import com.ippon.belt.service.MailService;
import com.ippon.belt.service.UserService;
import com.ippon.belt.service.dto.AdminUserDTO;
import com.ippon.belt.web.rest.errors.BadRequestAlertException;
import com.ippon.belt.web.rest.errors.EmailAlreadyUsedException;
import com.ippon.belt.web.rest.errors.LoginAlreadyUsedException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.Collections;
import javax.validation.Valid;
import javax.validation.constraints.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import tech.jhipster.web.util.HeaderUtil;
import tech.jhipster.web.util.PaginationUtil;
import tech.jhipster.web.util.ResponseUtil;
/**
* REST controller for managing users.
* <p>
* This class accesses the {@link User} entity, and needs to fetch its collection of authorities.
* <p>
* For a normal use-case, it would be better to have an eager relationship between User and Authority,
* and send everything to the client side: there would be no View Model and DTO, a lot less code, and an outer-join
* which would be good for performance.
* <p>
* We use a View Model and a DTO for 3 reasons:
* <ul>
* <li>We want to keep a lazy association between the user and the authorities, because people will
* quite often do relationships with the user, and we don't want them to get the authorities all
* the time for nothing (for performance reasons). This is the #1 goal: we should not impact our users'
* application because of this use-case.</li>
* <li> Not having an outer join causes n+1 requests to the database. This is not a real issue as
* we have by default a second-level cache. This means on the first HTTP call we do the n+1 requests,
* but then all authorities come from the cache, so in fact it's much better than doing an outer join
* (which will get lots of data from the database, for each HTTP call).</li>
* <li> As this manages users, for security reasons, we'd rather have a DTO layer.</li>
* </ul>
* <p>
* Another option would be to have a specific JPA entity graph to handle this case.
*/
@RestController
@RequestMapping("/api/admin")
public class UserResource {
private static final List<String> ALLOWED_ORDERED_PROPERTIES = Collections.unmodifiableList(
Arrays.asList(
"id",
"login",
"firstName",
"lastName",
"email",
"activated",
"langKey",
"createdBy",
"createdDate",
"lastModifiedBy",
"lastModifiedDate"
)
);
private final Logger log = LoggerFactory.getLogger(UserResource.class);
@Value("${jhipster.clientApp.name}")
private String applicationName;
private final UserService userService;
private final UserRepository userRepository;
private final MailService mailService;
public UserResource(UserService userService, UserRepository userRepository, MailService mailService) {
this.userService = userService;
this.userRepository = userRepository;
this.mailService = mailService;
}
/**
* {@code POST /admin/users} : Creates a new user.
* <p>
* Creates a new user if the login and email are not already used, and sends an
* mail with an activation link.
* The user needs to be activated on creation.
*
* @param userDTO the user to create.
* @return the {@link ResponseEntity} with status {@code 201 (Created)} and with body the new user, or with status {@code 400 (Bad Request)} if the login or email is already in use.
* @throws URISyntaxException if the Location URI syntax is incorrect.
* @throws BadRequestAlertException {@code 400 (Bad Request)} if the login or email is already in use.
*/
@PostMapping("/users")
@PreAuthorize("hasAuthority(\"" + AuthoritiesConstants.ADMIN + "\")")
public ResponseEntity<User> createUser(@Valid @RequestBody AdminUserDTO userDTO) throws URISyntaxException {
log.debug("REST request to save User : {}", userDTO);
if (userDTO.getId() != null) {
throw new BadRequestAlertException("A new user cannot already have an ID", "userManagement", "idexists");
// Lowercase the user login before comparing with database
} else if (userRepository.findOneByLogin(userDTO.getLogin().toLowerCase()).isPresent()) {
throw new LoginAlreadyUsedException();
} else if (userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()).isPresent()) {
throw new EmailAlreadyUsedException();
} else {
User newUser = userService.createUser(userDTO);
mailService.sendCreationEmail(newUser);
return ResponseEntity
.created(new URI("/api/admin/users/" + newUser.getLogin()))
.headers(HeaderUtil.createAlert(applicationName, "userManagement.created", newUser.getLogin()))
.body(newUser);
}
}
/**
* {@code PUT /admin/users} : Updates an existing User.
*
* @param userDTO the user to update.
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the updated user.
* @throws EmailAlreadyUsedException {@code 400 (Bad Request)} if the email is already in use.
* @throws LoginAlreadyUsedException {@code 400 (Bad Request)} if the login is already in use.
*/
@PutMapping("/users")
@PreAuthorize("hasAuthority(\"" + AuthoritiesConstants.ADMIN + "\")")
public ResponseEntity<AdminUserDTO> updateUser(@Valid @RequestBody AdminUserDTO userDTO) {
log.debug("REST request to update User : {}", userDTO);
Optional<User> existingUser = userRepository.findOneByEmailIgnoreCase(userDTO.getEmail());
if (existingUser.isPresent() && (!existingUser.get().getId().equals(userDTO.getId()))) {
throw new EmailAlreadyUsedException();
}
existingUser = userRepository.findOneByLogin(userDTO.getLogin().toLowerCase());
if (existingUser.isPresent() && (!existingUser.get().getId().equals(userDTO.getId()))) {
throw new LoginAlreadyUsedException();
}
Optional<AdminUserDTO> updatedUser = userService.updateUser(userDTO);
return ResponseUtil.wrapOrNotFound(
updatedUser,
HeaderUtil.createAlert(applicationName, "userManagement.updated", userDTO.getLogin())
);
}
/**
* {@code GET /admin/users} : get all users with all the details - calling this are only allowed for the administrators.
*
* @param pageable the pagination information.
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body all users.
*/
@GetMapping("/users")
@PreAuthorize("hasAuthority(\"" + AuthoritiesConstants.ADMIN + "\")")
public ResponseEntity<List<AdminUserDTO>> getAllUsers(Pageable pageable) {
log.debug("REST request to get all User for an admin");
if (!onlyContainsAllowedProperties(pageable)) {
return ResponseEntity.badRequest().build();
}
final Page<AdminUserDTO> page = userService.getAllManagedUsers(pageable);
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(ServletUriComponentsBuilder.fromCurrentRequest(), page);
return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
}
private boolean onlyContainsAllowedProperties(Pageable pageable) {
return pageable.getSort().stream().map(Sort.Order::getProperty).allMatch(ALLOWED_ORDERED_PROPERTIES::contains);
}
/**
* {@code GET /admin/users/:login} : get the "login" user.
*
* @param login the login of the user to find.
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the "login" user, or with status {@code 404 (Not Found)}.
*/
@GetMapping("/users/{login}")
@PreAuthorize("hasAuthority(\"" + AuthoritiesConstants.ADMIN + "\")")
public ResponseEntity<AdminUserDTO> getUser(@PathVariable @Pattern(regexp = Constants.LOGIN_REGEX) String login) {
log.debug("REST request to get User : {}", login);
return ResponseUtil.wrapOrNotFound(userService.getUserWithAuthoritiesByLogin(login).map(AdminUserDTO::new));
}
/**
* {@code DELETE /admin/users/:login} : delete the "login" User.
*
* @param login the login of the user to delete.
* @return the {@link ResponseEntity} with status {@code 204 (NO_CONTENT)}.
*/
@DeleteMapping("/users/{login}")
@PreAuthorize("hasAuthority(\"" + AuthoritiesConstants.ADMIN + "\")")
public ResponseEntity<Void> deleteUser(@PathVariable @Pattern(regexp = Constants.LOGIN_REGEX) String login) {
log.debug("REST request to delete User: {}", login);
userService.deleteUser(login);
return ResponseEntity.noContent().headers(HeaderUtil.createAlert(applicationName, "userManagement.deleted", login)).build();
}
}