SUPPORT-9001: reset-pass

This commit is contained in:
adel.ka 2025-03-13 22:37:28 +03:00
parent 2bc376eafa
commit a1e3797486
18 changed files with 190 additions and 19 deletions

View file

@ -13,10 +13,7 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestTemplate;
@ -36,6 +33,10 @@ import ru.micord.ervu.account_applications.dto.deactivate.DeactivateProcessReque
import ru.micord.ervu.account_applications.dto.edit.EditData;
import ru.micord.ervu.account_applications.dto.edit.EditPersonDto;
import ru.micord.ervu.account_applications.dto.edit.EditPersonProcessRequest;
import ru.micord.ervu.account_applications.dto.password.ResetPasswordData;
import ru.micord.ervu.account_applications.dto.password.ResetPasswordDto;
import ru.micord.ervu.account_applications.dto.password.ResetPasswordProcessRequest;
import ru.micord.ervu.account_applications.dto.password.UserIdInfo;
import ru.micord.ervu.account_applications.enums.ProcessKey;
import ru.micord.ervu.account_applications.security.context.SecurityContext;
import ru.micord.ervu.account_applications.service.UserApplicationListService;
@ -100,6 +101,30 @@ public class AdminController {
return doRequest(request);
}
@GetMapping("/exists")
public ResponseEntity<Boolean> userExists(@RequestParam(name = "login") String login) {
boolean result = applicationListService.userExists(login);
return ResponseEntity.ok(result);
}
@PostMapping(value = "/password/reset")
public ResponseEntity<?> resetPassword(@RequestBody ResetPasswordDto dto){
ResetPasswordProcessRequest request = new ResetPasswordProcessRequest(ProcessKey.RESET_PASSWORD.getValue(),
getUserId(), new ResetPasswordData(new UserIdInfo(dto.accountId())));
ResponseEntity<?> responseEntity = doRequest(request);
if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
String traceId = ((ProcessResponse) Objects.requireNonNull(responseEntity.getBody())).traceId();
applicationListService.saveTraceId(traceId, dto.appNumber());
}
return responseEntity;
}
@GetMapping("/password/check")
public ResponseEntity<Boolean> passwordCheck(@RequestParam(name = "login") String login) {
boolean result = applicationListService.isPasswordExpired(login);
return ResponseEntity.ok(result);
}
private <R> ResponseEntity<?> doRequest(ProcessRequest<R> request) {
HttpEntity<ProcessRequest<R>> entity = setEntity(getToken(), request);
URI uri = UriComponentsBuilder.fromHttpUrl(ervuUrl)

View file

@ -1,5 +1,9 @@
package ru.micord.ervu.account_applications.dao;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Optional;
import org.jooq.DSLContext;
import org.springframework.stereotype.Repository;
import ru.micord.ervu.account_applications.enums.ApplicationStatus;
@ -29,6 +33,7 @@ public class UserApplicationListDao {
dslContext.update(USER_APPLICATION_LIST)
.set(USER_APPLICATION_LIST.APPLICATION_STATUS, ApplicationStatus.ACCEPTED.name())
.set(USER_APPLICATION_LIST.USER_PASSWORD, encodedPass)
.set(USER_APPLICATION_LIST.PASSWORD_LAST_UPDATED, Timestamp.valueOf(LocalDateTime.now()))
.where(USER_APPLICATION_LIST.TRACE_ID.eq(traceId))
.execute();
}
@ -47,4 +52,18 @@ public class UserApplicationListDao {
.where(USER_APPLICATION_LIST.TRACE_ID.eq(traceId))
.execute();
}
public boolean userExists(String login) {
return dslContext.fetchExists(
dslContext.selectOne()
.from(USER_APPLICATION_LIST)
.where(USER_APPLICATION_LIST.USER_LOGIN.eq(login)));
}
public Optional<LocalDateTime> getPasswordLastUpdated(String login) {
return dslContext.select(USER_APPLICATION_LIST.PASSWORD_LAST_UPDATED)
.from(USER_APPLICATION_LIST)
.where(USER_APPLICATION_LIST.USER_LOGIN.eq(login))
.fetchOptionalInto(LocalDateTime.class);
}
}

View file

@ -242,6 +242,13 @@ public class UserApplicationList extends TableImpl<UserApplicationListRecord> {
*/
public final TableField<UserApplicationListRecord, String> TRACE_ID = createField(DSL.name("trace_id"), SQLDataType.VARCHAR(36), this, "Идентификатор процесса");
/**
* The column
* <code>public.user_application_list.password_last_updated</code>. Дата
* последнего обновления пароля
*/
public final TableField<UserApplicationListRecord, Timestamp> PASSWORD_LAST_UPDATED = createField(DSL.name("password_last_updated"), SQLDataType.TIMESTAMP(0), this, "Дата последнего обновления пароля");
private UserApplicationList(Name alias, Table<UserApplicationListRecord> aliased) {
this(alias, aliased, (Field<?>[]) null, null);
}

View file

@ -506,6 +506,24 @@ public class UserApplicationListRecord extends UpdatableRecordImpl<UserApplicati
return (String) get(30);
}
/**
* Setter for
* <code>public.user_application_list.password_last_updated</code>. Дата
* последнего обновления пароля
*/
public void setPasswordLastUpdated(Timestamp value) {
set(31, value);
}
/**
* Getter for
* <code>public.user_application_list.password_last_updated</code>. Дата
* последнего обновления пароля
*/
public Timestamp getPasswordLastUpdated() {
return (Timestamp) get(31);
}
// -------------------------------------------------------------------------
// Primary key information
// -------------------------------------------------------------------------
@ -529,7 +547,7 @@ public class UserApplicationListRecord extends UpdatableRecordImpl<UserApplicati
/**
* Create a detached, initialised UserApplicationListRecord
*/
public UserApplicationListRecord(Long userApplicationListId, String applicationKind, String userLogin, String userPassword, String secondname, String firstname, String middlename, String phone, Timestamp startDate, Timestamp closeDate, String userStatus, String applicationStatus, String comment, Long jobPositionId, Long userRoleId, UUID recruitmentId, String userAccountId, String sex, Date birthDate, String snils, String jobPosition, Long numberApp, String editComment, String personId, String updateSecondname, String updateFirstname, String updateMiddlename, String updateSex, Date updateBirthDate, String updateJobPosition, String traceId) {
public UserApplicationListRecord(Long userApplicationListId, String applicationKind, String userLogin, String userPassword, String secondname, String firstname, String middlename, String phone, Timestamp startDate, Timestamp closeDate, String userStatus, String applicationStatus, String comment, Long jobPositionId, Long userRoleId, UUID recruitmentId, String userAccountId, String sex, Date birthDate, String snils, String jobPosition, Long numberApp, String editComment, String personId, String updateSecondname, String updateFirstname, String updateMiddlename, String updateSex, Date updateBirthDate, String updateJobPosition, String traceId, Timestamp passwordLastUpdated) {
super(UserApplicationList.USER_APPLICATION_LIST);
setUserApplicationListId(userApplicationListId);
@ -563,6 +581,7 @@ public class UserApplicationListRecord extends UpdatableRecordImpl<UserApplicati
setUpdateBirthDate(updateBirthDate);
setUpdateJobPosition(updateJobPosition);
setTraceId(traceId);
setPasswordLastUpdated(passwordLastUpdated);
resetChangedOnNotNull();
}
}

View file

@ -0,0 +1,8 @@
package ru.micord.ervu.account_applications.dto.password;
/**
* @author Adel Kalimullin
*/
public record ResetPasswordData(UserIdInfo account) {
}

View file

@ -0,0 +1,7 @@
package ru.micord.ervu.account_applications.dto.password;
/**
* @author Adel Kalimullin
*/
public record ResetPasswordDto(long appNumber, String accountId) {
}

View file

@ -0,0 +1,13 @@
package ru.micord.ervu.account_applications.dto.password;
import ru.micord.ervu.account_applications.dto.ProcessRequest;
/**
* @author Adel Kalimullin
*/
public class ResetPasswordProcessRequest extends ProcessRequest {
public ResetPasswordProcessRequest(String processKey, String userId, Object data) {
super(processKey, userId, data);
}
}

View file

@ -0,0 +1,7 @@
package ru.micord.ervu.account_applications.dto.password;
/**
* @author Adel Kalimullin
*/
public record UserIdInfo(String id){
}

View file

@ -8,7 +8,8 @@ public enum ProcessKey {
EDIT_PERSON("milBaseEditAccountPersonIDMProcess"),
EDIT_ACCOUNT("milBaseEditAccountIDMProcess"),
EDIT_ROLES("milBaseEditAccountRolesIDMSubProcess"),
DEACTIVATE("milBaseMassDeActivateAccountIDMProcess");
DEACTIVATE("milBaseMassDeActivateAccountIDMProcess"),
RESET_PASSWORD("milBaseResetPasswordProcess");
private final String value;

View file

@ -37,7 +37,7 @@ public class AccountServiceImpl extends AbstractUserDataService {
private Account fetchAccountById(Object id) throws IOException, InterruptedException {
String url = UriComponentsBuilder.fromHttpUrl(ervuUrl)
.pathSegment(PathConstant.ACCOUNTS_PATH)
.path(PathConstant.ACCOUNTS_PATH)
.pathSegment(id.toString())
.queryParam("expand", "person,user-domain,region")
.toUriString();

View file

@ -35,7 +35,7 @@ public class RoleServiceImpl extends AbstractUserDataService {
private List<Role> fetchRolesByAccountId(Object accountId) throws IOException, InterruptedException {
String url = UriComponentsBuilder.fromHttpUrl(ervuUrl)
.pathSegment(PathConstant.ACCOUNTS_PATH)
.path(PathConstant.ACCOUNTS_PATH)
.pathSegment(accountId.toString())
.pathSegment(ROLES)
.toUriString();

View file

@ -1,5 +1,8 @@
package ru.micord.ervu.account_applications.service;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import org.springframework.stereotype.Service;
import ru.micord.ervu.account_applications.dao.UserApplicationListDao;
@ -23,6 +26,16 @@ public class UserApplicationListService {
dao.savePassword(traceId, encodedPass);
}
public boolean userExists(String login){
return dao.userExists(login);
}
public boolean isPasswordExpired(String login) {
return dao.getPasswordLastUpdated(login)
.map(date -> ChronoUnit.DAYS.between(date, LocalDateTime.now()) > 20)
.orElse(true);
}
public void saveAcceptedStatus(String traceId) {
dao.saveAcceptedStatus(traceId);
}

View file

@ -2,15 +2,12 @@ package ru.micord.ervu.account_applications.service;
import java.io.IOException;
import java.net.http.HttpResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.CollectionType;
import model.grid.GridRow;
import model.grid.GridRows;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;
import ru.micord.ervu.account_applications.component.model.Credential;
@ -36,7 +33,7 @@ public class UserCredentialsServiceIpml extends AbstractUserDataService {
private List<Credential> fetchCredentialsByPersonId(Object personId) throws IOException, InterruptedException {
String url = UriComponentsBuilder.fromHttpUrl(ervuUrl)
.pathSegment(PathConstant.PERSONS_PATH)
.path(PathConstant.PERSONS_PATH)
.pathSegment(personId.toString())
.pathSegment(CREDENTIALS)
.toUriString();

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog/1.9"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog/1.9
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-1.9.xsd">
<changeSet id="0001" author="a.kalimullin">
<comment>add password_last_updated column to user_application_list table</comment>
<sql>
ALTER TABLE user_application_list ADD COLUMN IF NOT EXISTS password_last_updated TIMESTAMP;
COMMENT ON COLUMN user_application_list.password_last_updated IS 'Дата последнего обновления пароля';
</sql>
</changeSet>
</databaseChangeLog>

View file

@ -15,6 +15,7 @@
<include file="20250304_SUPPORT-8956_drop_security.xml" relativeToChangelogFile="true"/>
<include file="20250307_ERVU-308_create_table_update.xml" relativeToChangelogFile="true"/>
<include file="20250312-SUPPORT-8696_add_column_role.xml" relativeToChangelogFile="true"/>
<include file="20250314_add_password_last_update.xml" relativeToChangelogFile="true"/>

View file

@ -1,9 +1,4 @@
import {
AnalyticalScope,
Behavior,
NotNull,
SaveButton
} from "@webbpm/base-package";
import {AnalyticalScope, Behavior, NotNull, SaveButton} from "@webbpm/base-package";
import {HttpClient} from "@angular/common/http";
import {FormField} from "../field/FormField";
import {AccountAction} from "../enum/AccountAction";
@ -40,6 +35,8 @@ export class UserManagementService extends Behavior {
case AccountAction.DEACTIVATE:
this.doRequest("user/deactivate", jsonObj);
break;
case AccountAction.RESET_PASSWORD:
this.doRequest("user/password-reset",jsonObj);
}
}
}

View file

@ -1,5 +1,6 @@
export enum AccountAction {
CREATE = "CREATE",
EDIT = "EDIT",
DEACTIVATE = "DEACTIVATE"
DEACTIVATE = "DEACTIVATE",
RESET_PASSWORD="RESET_PASSWORD"
}

View file

@ -0,0 +1,40 @@
import {AnalyticalScope, Behavior, Control, ControlWithValue, Visible,} from "@webbpm/base-package";
import {HttpClient} from "@angular/common/http";
@AnalyticalScope(Control)
export class FieldChecker extends Behavior {
private client: HttpClient;
private control: ControlWithValue;
initialize() {
this.client = this.injector.get(HttpClient);
this.control = this.getScript('component.ControlWithValue');
}
@Visible()
passwordCheck(login: string) {
return this.client.get<boolean>(`user/password/check?login=${encodeURIComponent(login)}`)
.toPromise()
.then((isExpired: boolean) => {
this.control.setValue(isExpired);
})
.catch((error) => {
console.error("Ошибка при проверке пароля:", error);
this.control.setValue(null);
});
}
@Visible()
userExists(login: string) {
return this.client.get<boolean>(`user/exists?login=${encodeURIComponent(login)}`)
.toPromise()
.then((exists: boolean) => {
this.control.setValue(exists);
})
.catch((error) => {
console.error("Ошибка при проверке пользователя:", error);
this.control.setValue(null);
});
}
}