diff --git a/backend/src/main/java/com/park/utmstack/service/DefinitionSyncService.java b/backend/src/main/java/com/park/utmstack/service/DefinitionSyncService.java index d841ea354..a2c548ab0 100644 --- a/backend/src/main/java/com/park/utmstack/service/DefinitionSyncService.java +++ b/backend/src/main/java/com/park/utmstack/service/DefinitionSyncService.java @@ -18,8 +18,8 @@ import org.slf4j.LoggerFactory; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import org.yaml.snakeyaml.Yaml; +import org.springframework.transaction.annotation.Transactional; import javax.validation.ConstraintViolation; import javax.validation.Validator; diff --git a/backend/src/main/java/com/park/utmstack/service/UserService.java b/backend/src/main/java/com/park/utmstack/service/UserService.java index 1510649f3..301d9d1ca 100644 --- a/backend/src/main/java/com/park/utmstack/service/UserService.java +++ b/backend/src/main/java/com/park/utmstack/service/UserService.java @@ -129,6 +129,14 @@ private boolean removeNonActivatedUser(User existingUser) { } public User createUser(UserDTO userDTO) { + return createUser(userDTO, null); + } + + /** + * Create a user. When a local password is provided the user is activated + * immediately, no email/activation step is needed. + */ + public User createUser(UserDTO userDTO, String localPassword) { String ctx = CLASS_NAME + ".createUser"; try { User user = new User(); @@ -142,11 +150,16 @@ public User createUser(UserDTO userDTO) { } else { user.setLangKey(userDTO.getLangKey()); } - String encryptedPassword = passwordEncoder.encode(RandomUtil.generatePassword()); - user.setPassword(encryptedPassword); - user.setResetKey(RandomUtil.generateResetKey()); - user.setResetDate(Instant.now()); - user.setActivated(false); + if (StringUtils.hasText(localPassword)) { + user.setPassword(passwordEncoder.encode(localPassword)); + user.setActivated(true); + } else { + String encryptedPassword = passwordEncoder.encode(RandomUtil.generatePassword()); + user.setPassword(encryptedPassword); + user.setResetKey(RandomUtil.generateResetKey()); + user.setResetDate(Instant.now()); + user.setActivated(false); + } if (userDTO.getAuthorities() != null) { Set authorities = userDTO.getAuthorities().stream().map(authorityRepository::findById).filter( Optional::isPresent).map(Optional::get).collect(Collectors.toSet()); diff --git a/backend/src/main/java/com/park/utmstack/web/rest/UserResource.java b/backend/src/main/java/com/park/utmstack/web/rest/UserResource.java index b74256667..ccb79c5ea 100644 --- a/backend/src/main/java/com/park/utmstack/web/rest/UserResource.java +++ b/backend/src/main/java/com/park/utmstack/web/rest/UserResource.java @@ -16,6 +16,7 @@ import com.park.utmstack.web.rest.errors.LoginAlreadyUsedException; import com.park.utmstack.web.rest.util.HeaderUtil; import com.park.utmstack.web.rest.util.PaginationUtil; +import com.park.utmstack.web.rest.vm.ManagedUserVM; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.domain.Page; @@ -25,6 +26,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import tech.jhipster.web.util.ResponseUtil; @@ -130,6 +132,37 @@ public ResponseEntity createUser(@Valid @RequestBody UserDTO userDTO) { } } + @PostMapping("/users/local") + @PreAuthorize("hasRole(\"" + AuthoritiesConstants.ADMIN + "\")") + @AuditEvent( + attemptType = ApplicationEventType.USER_CREATION_ATTEMPT, + attemptMessage = "Attempting to create user {login} locally", + successType = ApplicationEventType.USER_CREATION_SUCCESS, + successMessage = "User {login} created locally (no email activation)" + ) + public ResponseEntity createUserLocal(@Valid @RequestBody ManagedUserVM userDTO) { + if (userDTO.getId() != null) { + throw new BadRequestAlertException("A new user cannot already have an ID", "userManagement", "idexists"); + } + if (userRepository.findOneByLogin(userDTO.getLogin() + .toLowerCase()) + .isPresent()) { + throw new LoginAlreadyUsedException(); + } + if (userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()) + .isPresent()) { + throw new EmailAlreadyUsedException(); + } + if (!StringUtils.hasText(userDTO.getPassword()) || userDTO.getPassword().length() <= 4) { + throw new BadRequestAlertException("Password is invalid: it must be longer than 4 characters", "userManagement", "invalidpassword"); + } + User newUser = userService.createUser(userDTO, userDTO.getPassword()); + return ResponseEntity.created(new URI("/api/users/" + newUser.getLogin())) + .headers(HeaderUtil.createAlert("A user is created with identifier " + newUser.getLogin(), + newUser.getLogin())) + .body(newUser); + } + /** * PUT /users : Updates an existing User. * diff --git a/frontend/src/app/admin/user/user-update/user-management-update.component.html b/frontend/src/app/admin/user/user-update/user-management-update.component.html index 940c3cdd3..933785228 100644 --- a/frontend/src/app/admin/user/user-update/user-management-update.component.html +++ b/frontend/src/app/admin/user/user-update/user-management-update.component.html @@ -1,106 +1,212 @@ - +
-
+
- +
- + This field is required. - + This field cannot be longer than 50 characters. - + This field can only contain letters, digits and e-mail addresses.
- +
- + This field cannot be longer than 50 characters.
- +
- + This field cannot be longer than 50 characters.
- +
- + This field is required. - + This field cannot be longer than 100 characters. - + This field is required to be at least 5 characters. - + Your email is invalid.
+
+ +
+
+ + + +
+ + This field is required. + + + + This field is required to be at least 4 characters. + + + + This field cannot be longer than 100 characters. + +
+
- + - + This field is required. You must select a role.
-
- -
- diff --git a/frontend/src/app/admin/user/user-update/user-management-update.component.ts b/frontend/src/app/admin/user/user-update/user-management-update.component.ts index e16e677ae..8a283e4ef 100644 --- a/frontend/src/app/admin/user/user-update/user-management-update.component.ts +++ b/frontend/src/app/admin/user/user-update/user-management-update.component.ts @@ -1,16 +1,15 @@ -import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; -import {NgbActiveModal, NgbModal} from '@ng-bootstrap/ng-bootstrap'; -import {User} from '../../../core/user/user.model'; -import {UserService} from '../../../core/user/user.service'; -import {UtmToastService} from '../../../shared/alert/utm-toast.service'; -import {ContactUsComponent} from '../../../shared/components/contact-us/contact-us.component'; -import {DEMO_URL} from '../../../shared/constants/global.constant'; - +import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core"; +import { NgbActiveModal, NgbModal } from "@ng-bootstrap/ng-bootstrap"; +import { User } from "../../../core/user/user.model"; +import { UserService } from "../../../core/user/user.service"; +import { UtmToastService } from "../../../shared/alert/utm-toast.service"; +import { ContactUsComponent } from "../../../shared/components/contact-us/contact-us.component"; +import { DEMO_URL } from "../../../shared/constants/global.constant"; @Component({ - selector: 'app-user-mgmt-update', - templateUrl: './user-management-update.component.html', - styleUrls: ['./user-managment-update.component.scss'] + selector: "app-user-mgmt-update", + templateUrl: "./user-management-update.component.html", + styleUrls: ["./user-managment-update.component.scss"], }) export class UserMgmtUpdateComponent implements OnInit { @Input() user: User; @@ -19,17 +18,19 @@ export class UserMgmtUpdateComponent implements OnInit { authorities: any[]; isSaving: boolean; creating = false; + localCreation = false; - constructor(private userService: UserService, - public activeModal: NgbActiveModal, - private utmToast: UtmToastService, - private modalService: NgbModal) { - } + constructor( + private userService: UserService, + public activeModal: NgbActiveModal, + private utmToast: UtmToastService, + private modalService: NgbModal, + ) {} ngOnInit() { this.isSaving = false; this.authorities = []; - this.userService.authorities().subscribe(authorities => { + this.userService.authorities().subscribe((authorities) => { this.authorities = authorities; }); if (!this.user) { @@ -45,41 +46,55 @@ export class UserMgmtUpdateComponent implements OnInit { if (!window.location.href.includes(DEMO_URL)) { this.isSaving = true; if (this.user.id !== null) { - this.userService.update(this.user) - .subscribe(response => this.onSaveSuccess(response, 'update'), - (error) => this.onSaveError(error, 'update')); + this.userService.update(this.user).subscribe( + (response) => this.onSaveSuccess(response, "update"), + (error) => this.onSaveError(error, "update"), + ); } else { - this.user.langKey = 'en'; - this.userService.create(this.user) - .subscribe(response => this.onSaveSuccess(response, 'create'), - (error) => this.onSaveError(error, 'create')); + this.user.langKey = "en"; + if (this.localCreation) { + this.userService.createLocal(this.user).subscribe( + (response) => this.onSaveSuccess(response, "create"), + (error) => this.onSaveError(error, "create"), + ); + } else { + this.userService.create(this.user).subscribe( + (response) => this.onSaveSuccess(response, "create"), + (error) => this.onSaveError(error, "create"), + ); + } } } else { - this.modalService.open(ContactUsComponent, {centered: true}); + this.modalService.open(ContactUsComponent, { centered: true }); } } - addRol(roleadmin: string) { - } + addRol(roleadmin: string) {} private onSaveSuccess(result, type) { this.isSaving = false; - if (type === 'update') { - this.utmToast.showSuccess('User updated successfully'); + if (type === "update") { + this.utmToast.showSuccess("User updated successfully"); } else { - this.utmToast.showSuccess('User created successfully'); + this.utmToast.showSuccess("User created successfully"); } this.activeModal.close(); - this.userChange.emit('changed'); + this.userChange.emit("changed"); } private onSaveError(error, type) { this.isSaving = false; if (error.status === 400) { - this.utmToast.showError('Error', 'Admin role removal is prohibited for the last remaining administrator user.'); + this.utmToast.showError( + "Error", + "Admin role removal is prohibited for the last remaining administrator user.", + ); } else { - this.utmToast.showError('Problem', 'The login or email is already in use, please check'); + this.utmToast.showError( + "Problem", + "The login or email is already in use, please check", + ); } } } diff --git a/frontend/src/app/admin/user/user-update/user-managment-update.component.scss b/frontend/src/app/admin/user/user-update/user-managment-update.component.scss index 7bb2f9da4..a6d5f7dbd 100644 --- a/frontend/src/app/admin/user/user-update/user-managment-update.component.scss +++ b/frontend/src/app/admin/user/user-update/user-managment-update.component.scss @@ -1,3 +1,7 @@ +.ml-12{ + margin-left:1.7rem; +} + .update-user-container { //background-color: #f1f1f1; padding-top: 30px; diff --git a/frontend/src/app/core/user/user.service.ts b/frontend/src/app/core/user/user.service.ts index 77f100bdb..4d174ea81 100644 --- a/frontend/src/app/core/user/user.service.ts +++ b/frontend/src/app/core/user/user.service.ts @@ -1,40 +1,57 @@ import {HttpClient, HttpResponse} from '@angular/common/http'; -import {Injectable} from '@angular/core'; -import {Observable} from 'rxjs'; +import { Injectable } from "@angular/core"; +import { Observable } from "rxjs"; -import {SERVER_API_URL} from '../../app.constants'; -import {createRequestOption} from '../../shared/util/request-util'; -import {IUser, User} from './user.model'; +import { SERVER_API_URL } from "../../app.constants"; +import { createRequestOption } from "../../shared/util/request-util"; +import { IUser, User } from "./user.model"; -@Injectable({providedIn: 'root'}) +@Injectable({ providedIn: "root" }) export class UserService { - public resourceUrl = SERVER_API_URL + 'api/users'; + public resourceUrl = SERVER_API_URL + "api/users"; constructor(private http: HttpClient) { } create(user: IUser): Observable> { - return this.http.post(this.resourceUrl, user, {observe: 'response'}); + return this.http.post(this.resourceUrl, user, { + observe: "response", + }); + } + + createLocal(user: IUser): Observable> { + return this.http.post(this.resourceUrl + "/local", user, { + observe: "response", + }); } update(user: IUser): Observable> { - return this.http.put(this.resourceUrl, user, {observe: 'response'}); + return this.http.put(this.resourceUrl, user, { + observe: "response", + }); } find(login: string): Observable> { - return this.http.get(`${this.resourceUrl + '/filter'}/${login}`, {observe: 'response'}); + return this.http.get(`${this.resourceUrl + "/filter"}/${login}`, { + observe: "response", + }); } query(req?: any): Observable> { const options = createRequestOption(req); - return this.http.get(this.resourceUrl, {params: options, observe: 'response'}); + return this.http.get(this.resourceUrl, { + params: options, + observe: "response", + }); } delete(login: string): Observable> { - return this.http.delete(`${this.resourceUrl}/${login}`, {observe: 'response'}); + return this.http.delete(`${this.resourceUrl}/${login}`, { + observe: "response", + }); } authorities(): Observable { - return this.http.get(SERVER_API_URL + 'api/users/authorities'); + return this.http.get(SERVER_API_URL + "api/users/authorities"); } }