Skip to content

Commit 2c22bcc

Browse files
authored
Merge pull request #2642 from utmstack/backlog/v11_local_user_creation
Backlog/v11 local user creation
2 parents 3872910 + 8995165 commit 2c22bcc

7 files changed

Lines changed: 286 additions & 98 deletions

File tree

‎backend/src/main/java/com/park/utmstack/service/DefinitionSyncService.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
import org.slf4j.LoggerFactory;
1919
import org.springframework.boot.CommandLineRunner;
2020
import org.springframework.stereotype.Service;
21-
import org.springframework.transaction.annotation.Transactional;
2221
import org.yaml.snakeyaml.Yaml;
22+
import org.springframework.transaction.annotation.Transactional;
2323

2424
import javax.validation.ConstraintViolation;
2525
import javax.validation.Validator;

‎backend/src/main/java/com/park/utmstack/service/UserService.java‎

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,14 @@ private boolean removeNonActivatedUser(User existingUser) {
129129
}
130130

131131
public User createUser(UserDTO userDTO) {
132+
return createUser(userDTO, null);
133+
}
134+
135+
/**
136+
* Create a user. When a local password is provided the user is activated
137+
* immediately, no email/activation step is needed.
138+
*/
139+
public User createUser(UserDTO userDTO, String localPassword) {
132140
String ctx = CLASS_NAME + ".createUser";
133141
try {
134142
User user = new User();
@@ -142,11 +150,16 @@ public User createUser(UserDTO userDTO) {
142150
} else {
143151
user.setLangKey(userDTO.getLangKey());
144152
}
145-
String encryptedPassword = passwordEncoder.encode(RandomUtil.generatePassword());
146-
user.setPassword(encryptedPassword);
147-
user.setResetKey(RandomUtil.generateResetKey());
148-
user.setResetDate(Instant.now());
149-
user.setActivated(false);
153+
if (StringUtils.hasText(localPassword)) {
154+
user.setPassword(passwordEncoder.encode(localPassword));
155+
user.setActivated(true);
156+
} else {
157+
String encryptedPassword = passwordEncoder.encode(RandomUtil.generatePassword());
158+
user.setPassword(encryptedPassword);
159+
user.setResetKey(RandomUtil.generateResetKey());
160+
user.setResetDate(Instant.now());
161+
user.setActivated(false);
162+
}
150163
if (userDTO.getAuthorities() != null) {
151164
Set<Authority> authorities = userDTO.getAuthorities().stream().map(authorityRepository::findById).filter(
152165
Optional::isPresent).map(Optional::get).collect(Collectors.toSet());

‎backend/src/main/java/com/park/utmstack/web/rest/UserResource.java‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import com.park.utmstack.web.rest.errors.LoginAlreadyUsedException;
1717
import com.park.utmstack.web.rest.util.HeaderUtil;
1818
import com.park.utmstack.web.rest.util.PaginationUtil;
19+
import com.park.utmstack.web.rest.vm.ManagedUserVM;
1920
import org.slf4j.Logger;
2021
import org.slf4j.LoggerFactory;
2122
import org.springframework.data.domain.Page;
@@ -25,6 +26,7 @@
2526
import org.springframework.http.ResponseEntity;
2627
import org.springframework.security.access.prepost.PreAuthorize;
2728
import org.springframework.util.CollectionUtils;
29+
import org.springframework.util.StringUtils;
2830
import org.springframework.web.bind.annotation.*;
2931
import tech.jhipster.web.util.ResponseUtil;
3032

@@ -130,6 +132,37 @@ public ResponseEntity<User> createUser(@Valid @RequestBody UserDTO userDTO) {
130132
}
131133
}
132134

135+
@PostMapping("/users/local")
136+
@PreAuthorize("hasRole(\"" + AuthoritiesConstants.ADMIN + "\")")
137+
@AuditEvent(
138+
attemptType = ApplicationEventType.USER_CREATION_ATTEMPT,
139+
attemptMessage = "Attempting to create user {login} locally",
140+
successType = ApplicationEventType.USER_CREATION_SUCCESS,
141+
successMessage = "User {login} created locally (no email activation)"
142+
)
143+
public ResponseEntity<User> createUserLocal(@Valid @RequestBody ManagedUserVM userDTO) {
144+
if (userDTO.getId() != null) {
145+
throw new BadRequestAlertException("A new user cannot already have an ID", "userManagement", "idexists");
146+
}
147+
if (userRepository.findOneByLogin(userDTO.getLogin()
148+
.toLowerCase())
149+
.isPresent()) {
150+
throw new LoginAlreadyUsedException();
151+
}
152+
if (userRepository.findOneByEmailIgnoreCase(userDTO.getEmail())
153+
.isPresent()) {
154+
throw new EmailAlreadyUsedException();
155+
}
156+
if (!StringUtils.hasText(userDTO.getPassword()) || userDTO.getPassword().length() <= 4) {
157+
throw new BadRequestAlertException("Password is invalid: it must be longer than 4 characters", "userManagement", "invalidpassword");
158+
}
159+
User newUser = userService.createUser(userDTO, userDTO.getPassword());
160+
return ResponseEntity.created(new URI("/api/users/" + newUser.getLogin()))
161+
.headers(HeaderUtil.createAlert("A user is created with identifier " + newUser.getLogin(),
162+
newUser.getLogin()))
163+
.body(newUser);
164+
}
165+
133166
/**
134167
* PUT /users : Updates an existing User.
135168
*

‎frontend/src/app/admin/user/user-update/user-management-update.component.html‎

Lines changed: 152 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,106 +1,212 @@
1-
<app-utm-modal-header [name]="user.id?'Edit user':'Create user'"></app-utm-modal-header>
1+
<app-utm-modal-header
2+
[name]="user.id ? 'Edit user' : 'Create user'"
3+
></app-utm-modal-header>
24
<div class="container-fluid p-3">
3-
<form #editForm="ngForm" (ngSubmit)="save()" class="form-user" name="editForm" novalidate role="form">
5+
<form
6+
#editForm="ngForm"
7+
(ngSubmit)="save()"
8+
class="form-user"
9+
name="editForm"
10+
novalidate
11+
role="form"
12+
>
413
<div class="form-group">
514
<label class="form-control-label">Login</label>
6-
<input #loginInput="ngModel" [(ngModel)]="user.login" class="form-control" maxlength="50"
7-
minlength="1" name="login" pattern="^[_.@A-Za-z0-9-]*$" required
8-
type="text">
15+
<input
16+
#loginInput="ngModel"
17+
[(ngModel)]="user.login"
18+
class="form-control"
19+
maxlength="50"
20+
minlength="1"
21+
name="login"
22+
pattern="^[_.@A-Za-z0-9-]*$"
23+
required
24+
type="text"
25+
/>
926

1027
<div *ngIf="loginInput.dirty && loginInput.invalid">
11-
<small *ngIf="loginInput.errors.required"
12-
class="form-text text-danger">
28+
<small *ngIf="loginInput.errors.required" class="form-text text-danger">
1329
This field is required.
1430
</small>
1531

16-
<small *ngIf="loginInput.errors.maxlength"
17-
class="form-text text-danger">
32+
<small
33+
*ngIf="loginInput.errors.maxlength"
34+
class="form-text text-danger"
35+
>
1836
This field cannot be longer than 50 characters.
1937
</small>
2038

21-
<small *ngIf="loginInput.errors.pattern"
22-
class="form-text text-danger">
39+
<small *ngIf="loginInput.errors.pattern" class="form-text text-danger">
2340
This field can only contain letters, digits and e-mail addresses.
2441
</small>
2542
</div>
2643
</div>
2744
<div class="form-group">
2845
<label class="form-control-label">First Name</label>
29-
<input #firstNameInput="ngModel" [(ngModel)]="user.firstName" class="form-control" maxlength="50"
30-
name="firstName" type="text">
46+
<input
47+
#firstNameInput="ngModel"
48+
[(ngModel)]="user.firstName"
49+
class="form-control"
50+
maxlength="50"
51+
name="firstName"
52+
type="text"
53+
/>
3154

3255
<div *ngIf="firstNameInput.dirty && firstNameInput.invalid">
33-
<small *ngIf="firstNameInput.errors.maxlength"
34-
class="form-text text-danger">
56+
<small
57+
*ngIf="firstNameInput.errors.maxlength"
58+
class="form-text text-danger"
59+
>
3560
This field cannot be longer than 50 characters.
3661
</small>
3762
</div>
3863
</div>
3964
<div class="form-group">
4065
<label>Last Name</label>
41-
<input #lastNameInput="ngModel" [(ngModel)]="user.lastName" class="form-control" maxlength="50"
42-
name="lastName" type="text">
66+
<input
67+
#lastNameInput="ngModel"
68+
[(ngModel)]="user.lastName"
69+
class="form-control"
70+
maxlength="50"
71+
name="lastName"
72+
type="text"
73+
/>
4374

4475
<div *ngIf="lastNameInput.dirty && lastNameInput.invalid">
45-
<small *ngIf="lastNameInput.errors.maxlength"
46-
class="form-text text-danger">
76+
<small
77+
*ngIf="lastNameInput.errors.maxlength"
78+
class="form-text text-danger"
79+
>
4780
This field cannot be longer than 50 characters.
4881
</small>
4982
</div>
5083
</div>
5184
<div class="form-group">
5285
<label class="form-control-label">Email</label>
53-
<input #emailInput="ngModel" [(ngModel)]="user.email" class="form-control" email
54-
maxlength="254" minlength="5" name="email" required type="email">
86+
<input
87+
#emailInput="ngModel"
88+
[(ngModel)]="user.email"
89+
class="form-control"
90+
email
91+
maxlength="254"
92+
minlength="5"
93+
name="email"
94+
required
95+
type="email"
96+
/>
5597

5698
<div *ngIf="emailInput.dirty && emailInput.invalid">
57-
<small *ngIf="emailInput.errors.required"
58-
class="form-text text-danger">
99+
<small *ngIf="emailInput.errors.required" class="form-text text-danger">
59100
This field is required.
60101
</small>
61102

62-
<small *ngIf="emailInput.errors.maxlength"
63-
class="form-text text-danger">
103+
<small
104+
*ngIf="emailInput.errors.maxlength"
105+
class="form-text text-danger"
106+
>
64107
This field cannot be longer than 100 characters.
65108
</small>
66109

67-
<small *ngIf="emailInput.errors.minlength"
68-
class="form-text text-danger">
110+
<small
111+
*ngIf="emailInput.errors.minlength"
112+
class="form-text text-danger"
113+
>
69114
This field is required to be at least 5 characters.
70115
</small>
71116

72-
<small *ngIf="emailInput.errors.email"
73-
class="form-text text-danger">
117+
<small *ngIf="emailInput.errors.email" class="form-text text-danger">
74118
Your email is invalid.
75119
</small>
76120
</div>
77121
</div>
122+
<div class="form-group ml-12" *ngIf="!user.id">
123+
<label
124+
for="localCreation"
125+
class="form-control-label d-flex justify-content-between align-items-center"
126+
>
127+
<span>Local creation (no email activation)</span>
128+
<input
129+
id="localCreation"
130+
class="form-check-input"
131+
name="localCreation"
132+
type="checkbox"
133+
[(ngModel)]="localCreation"
134+
/>
135+
</label>
136+
</div>
137+
<div class="form-group" *ngIf="localCreation && !user.id">
138+
<label class="form-control-label">Password</label>
139+
<input
140+
#passwordInput="ngModel"
141+
[(ngModel)]="user.password"
142+
class="form-control"
143+
maxlength="100"
144+
minlength="4"
145+
name="password"
146+
required
147+
type="password"
148+
/>
149+
150+
<div *ngIf="passwordInput.dirty && passwordInput.invalid">
151+
<small
152+
*ngIf="passwordInput.errors.required"
153+
class="form-text text-danger"
154+
>
155+
This field is required.
156+
</small>
157+
158+
<small
159+
*ngIf="passwordInput.errors.minlength"
160+
class="form-text text-danger"
161+
>
162+
This field is required to be at least 4 characters.
163+
</small>
164+
165+
<small
166+
*ngIf="passwordInput.errors.maxlength"
167+
class="form-text text-danger"
168+
>
169+
This field cannot be longer than 100 characters.
170+
</small>
171+
</div>
172+
</div>
78173
<div class="form-group">
79174
<label for="profile">Rol</label>
80-
<select [(ngModel)]="user.authorities" required class="form-control" id="profile" multiple name="authority">
81-
<option *ngFor="let authority of authorities" [value]="authority">{{authority}}</option>
175+
<select
176+
[(ngModel)]="user.authorities"
177+
required
178+
class="form-control"
179+
id="profile"
180+
multiple
181+
name="authority"
182+
>
183+
<option *ngFor="let authority of authorities" [value]="authority">
184+
{{ authority }}
185+
</option>
82186
</select>
83-
<small *ngIf="user.authorities && user.authorities.length === 0"
84-
class="form-text text-danger">
187+
<small
188+
*ngIf="user.authorities && user.authorities.length === 0"
189+
class="form-text text-danger"
190+
>
85191
This field is required. You must select a role.
86192
</small>
87193
</div>
88-
89194
</form>
90195
<div class="button-container d-flex justify-content-end mt-4">
91-
<button (click)="activeModal.close()" class="btn utm-button utm-button-grey mr-3">
92-
<i class="icon-cancel-circle2"></i>&nbsp;
93-
Cancel
196+
<button
197+
(click)="activeModal.close()"
198+
class="btn utm-button utm-button-grey mr-3"
199+
>
200+
<i class="icon-cancel-circle2"></i>&nbsp; Cancel
94201
</button>
95-
<button (click)="save()"
96-
[disabled]="!editForm.valid"
97-
class="btn utm-button utm-button-primary
98-
d-flex justify-content-center
99-
align-items-center">
100-
<i [ngClass]="isSaving?'icon-spinner2 spinner':'icon-user-plus'">
101-
</i>&nbsp;
102-
{{user.id ? 'Edit user' : 'Create user'}}
202+
<button
203+
(click)="save()"
204+
[disabled]="!editForm.valid"
205+
class="btn utm-button utm-button-primary d-flex justify-content-center align-items-center"
206+
>
207+
<i [ngClass]="isSaving ? 'icon-spinner2 spinner' : 'icon-user-plus'"> </i
208+
>&nbsp;
209+
{{ user.id ? "Edit user" : "Create user" }}
103210
</button>
104211
</div>
105212
</div>
106-

0 commit comments

Comments
 (0)