16 Commits

Author SHA1 Message Date
Rinjae a45819cbce Merge remote-tracking branch 'origin/master'
eapim-portal CI (from elink-portal-common) / build (push) Has been cancelled
2026-07-30 19:41:14 +09:00
Rinjae fe1138b480 GW 클라이언트 해지 처리 로직 추가 - BLOCK/DELETE 처리방식 지원
- APP 승인 시 GW 처리방식 설정 기능 추가 및 상세 표시
- DELETE 요청 처리 중 클라이언트 상태 동기화 로직 개선
- JSP에 GW 처리방식 선택 UI 및 승인 결과 표시 추가
2026-07-30 16:23:09 +09:00
eastargh 88c1cc4918 최종로그인일시 추가
eapim-portal CI (from elink-portal-common) / build (push) Has been cancelled
2026-07-30 14:58:47 +09:00
Rinjae 97b1e0a28a - MessageRequest 엔티티 전화번호 정규화 콜백 추가
eapim-portal CI (from elink-portal-common) / build (push) Has been cancelled
- 저장 시 phone 필드 하이픈 정규형 통일(PhoneNumberUtil)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 13:48:52 +09:00
Rinjae 31c08a7284 - PortalOrg 초기화 필드 추가(orgDesc, ipWhitelist 등)
eapim-portal CI (from elink-portal-common) / build (push) Has been cancelled
- ApiTesterFilter 디버깅 로직/유틸 추가(maskHeaders 등)
- jackson-core 취약점(CVSS 7.5) 수정 버전 업그레이드(2.18.6)
2026-07-29 20:20:43 +09:00
eastargh dc5d2df166 관리자 로그인 n회 실패시 계정 잠김 기능
eapim-portal CI (from elink-portal-common) / build (push) Has been cancelled
2026-07-29 15:12:18 +09:00
Rinjae e3619b385f 사용자 역할 변경 이력 엔티티 및 레포지토리 추가:
eapim-portal CI (from elink-portal-common) / build (push) Has been cancelled
- UserRoleHistory 엔티티 정의 및 필드 매핑
- UserRoleHistoryRepository 조회 메서드 구현
2026-07-27 20:11:20 +09:00
Rinjae 94724d3952 UUID v7 생성기 추가 - Hibernate IdentifierGenerator 구현
eapim-portal CI (from elink-portal-common) / build (push) Has been cancelled
2026-07-27 18:28:09 +09:00
Rinjae 6a64d35a94 로그인 및 인증 관련 엔티티, 레포지토리 개선:
eapim-portal CI (from elink-portal-common) / build (push) Has been cancelled
- 실패 사유/로그인 유형 코드 필드 추가(UserLog)
- 만료 인증번호 일괄 삭제 레포지토리 메서드 추가
- UUID v7 적용(TwoFactorAuth) - PK 정렬 효율 개선
- 인증번호 실패 사유 코드 추가(AuthNumberException)
2026-07-27 18:20:49 +09:00
eastargh 72d2150a6e sms->kakao로 통일
eapim-portal CI (from elink-portal-common) / build (push) Has been cancelled
2026-07-16 09:28:35 +09:00
Rinjae c8049dd881 Merge remote-tracking branch 'origin/master'
eapim-portal CI (from elink-portal-common) / build (push) Has been cancelled
2026-07-13 14:25:16 +09:00
Rinjae 2e2ac8f462 API 그룹 팝업 JSP 파일 추가 - 예제 코드 및 UI 구조 작성
Summernote 에디터 스타일 CSS 추가 - 텍스트 및 컴포넌트 스타일 정의
OpenAPI POC JS 파일 추가 - API 스펙 빌더 및 스텝별 렌더 구현
2026-07-13 14:25:09 +09:00
eastargh f3a9e19b89 Merge branch 'master' of https://git.eactive.synology.me:8090/eapim/djbank/elink-portal-common.git
eapim-portal CI (from elink-portal-common) / build (push) Has been cancelled
2026-07-13 13:21:57 +09:00
eastargh b5866b087d ums 설정 변경 2026-07-13 13:21:30 +09:00
Rinjae 6f00de61d9 Q&A 문의 공개범위 기능 추가
eapim-portal CI (from elink-portal-common) / build (push) Has been cancelled
- 공개범위 설정 기능 개발(ALL/ORG/PRIVATE) - 게시물/댓글 정교화
- 요청 및 DB 처리 확장 - UI, DTO, Service 계층 업데이트
- 감사 로그 및 조회수 처리 로직 추가
2026-07-13 11:32:34 +09:00
Rinjae e5d0acf694 PortalPropertyRepository 중복 키 조회 메서드 추가 - 무결성 점검용
eapim-portal CI (from elink-portal-common) / build (push) Has been cancelled
2026-07-06 19:45:52 +09:00
19 changed files with 389 additions and 16 deletions
@@ -0,0 +1,21 @@
package com.eactive.apim.portal.apprequest.entity;
/**
* API 이용해지(DELETE) 승인 시 게이트웨이 클라이언트(TSEAIAU01) 처리 방식.
* 승인 시점에 관리자가 선택하며 PTL_APP_REQUEST.GW_ACTION 에 영속화된다.
* null(미지정)은 BLOCK 과 동일하게 처리한다.
*/
public enum GwAction {
BLOCK("차단"),
DELETE("완전삭제");
private final String description;
GwAction(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
@@ -23,6 +23,8 @@ public interface AppRequestRepository extends BaseRepository<AppRequest, String>
List<AppRequest> findAllByOrgAndTypeIsInAndApproval_ApprovalStatusIn(PortalOrg org, List<AppRequestType> types, List<ApprovalState> approvalStates);
List<AppRequest> findAllByOrgAndTypeIsInAndApprovalIsNull(PortalOrg org, List<AppRequestType> types);
int countAllByOrgAndTypeIsInAndApproval_ApprovalStatusIn(PortalOrg org, List<AppRequestType> types, List<ApprovalState> approvalStates);
Optional<AppRequest> findByIdAndOrg(String id, PortalOrg org);
@@ -0,0 +1,66 @@
package com.eactive.apim.portal.jpa;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentifierGenerator;
import java.io.Serializable;
import java.security.SecureRandom;
/**
* UUID version 7 (time-ordered, RFC 9562) 생성기.
*
* <p>상위 48비트에 Unix epoch 밀리초 타임스탬프를 두어 생성 시각 순으로 정렬되므로,
* 무작위 v4 대비 인덱스(B-Tree) 삽입 지역성이 좋아 PK 인덱스 단편화를 줄인다.
* canonical 36자 문자열로 반환하여 기존 {@code VARCHAR2(36)} 컬럼과 호환된다.</p>
*
* <p>레이아웃(128비트): unix_ts_ms(48) | ver=0b0111(4) | rand_a(12) | var=0b10(2) | rand_b(62)</p>
*
* <p>Java 8 호환(java.util.UUID + SecureRandom). Hibernate {@link IdentifierGenerator} 구현이며
* 엔티티에서 {@code @GenericGenerator(strategy = "...UuidV7Generator")} 로 지정한다.</p>
*/
public class UuidV7Generator implements IdentifierGenerator {
private static final SecureRandom RANDOM = new SecureRandom();
@Override
public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
return generateString();
}
/** UUID v7 을 canonical 36자 문자열로 생성한다. */
public static String generateString() {
long timestamp = System.currentTimeMillis();
byte[] value = new byte[16];
// 상위 48비트: unix epoch millis (big-endian)
value[0] = (byte) ((timestamp >>> 40) & 0xFF);
value[1] = (byte) ((timestamp >>> 32) & 0xFF);
value[2] = (byte) ((timestamp >>> 24) & 0xFF);
value[3] = (byte) ((timestamp >>> 16) & 0xFF);
value[4] = (byte) ((timestamp >>> 8) & 0xFF);
value[5] = (byte) (timestamp & 0xFF);
// 나머지 10바이트는 난수로 채운다.
byte[] rand = new byte[10];
RANDOM.nextBytes(rand);
System.arraycopy(rand, 0, value, 6, 10);
// version 7: value[6] 상위 니블을 0111 로 설정
value[6] = (byte) ((value[6] & 0x0F) | 0x70);
// variant 10xx: value[8] 상위 2비트를 10 으로 설정
value[8] = (byte) ((value[8] & 0x3F) | 0x80);
long msb = 0L;
for (int i = 0; i < 8; i++) {
msb = (msb << 8) | (value[i] & 0xFFL);
}
long lsb = 0L;
for (int i = 8; i < 16; i++) {
lsb = (lsb << 8) | (value[i] & 0xFFL);
}
return new java.util.UUID(msb, lsb).toString();
}
}
@@ -121,5 +121,8 @@ public class PortalOrg extends Auditable implements Serializable, com.eactive.ea
this.orgSectors = null;
this.orgIndustryType = null;
this.serviceName = null;
this.orgDesc = null;
this.ipWhitelist = null;
this.reverseProxyPath = null;
}
}
@@ -4,8 +4,23 @@ import com.eactive.apim.portal.portalproperty.entity.PortalProperty;
import com.eactive.apim.portal.portalproperty.entity.PortalPropertyId;
import com.eactive.eai.data.jpa.BaseRepository;
import com.eactive.eai.rms.data.EMSDataSource;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
@EMSDataSource
public interface PortalPropertyRepository extends BaseRepository<PortalProperty, PortalPropertyId> {
/**
* (PROPERTY_GROUP_NAME, PROPERTY_NAME) 조합이 2건 이상인 중복 키를 조회한다.
* DB에 유니크 제약을 걸지 않으므로 기동 시 무결성 점검용으로 사용한다.
*
* @return {@code Object[]{propertyGroupName, propertyName, count}} 목록 (중복 없으면 빈 리스트)
*/
@Query("SELECT p.id.propertyGroupName, p.id.propertyName, COUNT(p) "
+ "FROM PortalProperty p "
+ "GROUP BY p.id.propertyGroupName, p.id.propertyName "
+ "HAVING COUNT(p) > 1")
List<Object[]> findDuplicatePropertyKeys();
}
@@ -51,13 +51,24 @@ public class PortalPropertyService extends AbstractDataService<PortalPropertyGro
Optional<PortalProperty> existingProperty = portalPropertyRepository.findById(propertyId);
if (existingProperty.isPresent()) {
return existingProperty.get().getPropertyValue();
PortalProperty property = existingProperty.get();
// 설명(property_desc)이 비어 있으면 코드가 넘긴 description 으로 채운다.
// (값이 있으면 관리자 편집분 보존 — 덮어쓰지 않음)
if (isBlank(property.getPropertyDesc()) && !isBlank(description)) {
property.setPropertyDesc(description);
portalPropertyRepository.save(property);
}
return property.getPropertyValue();
}
// 프로퍼티가 없으면 기본값으로 생성
return createDefaultProperty(groupName, propertyName, defaultValue, description);
}
private static boolean isBlank(String s) {
return s == null || s.trim().isEmpty();
}
/**
* 기본 프로퍼티를 DB에 생성
*/
@@ -88,7 +88,11 @@ public class PortalUser extends Auditable implements Serializable, com.eactive.e
@Comment("로그인실패횟수")
private Integer loginFailureCount;
@Column(name = "password_change_date")
// PASSWORD_CHANGE_DATE 컬럼은 VARCHAR2(14) yyyyMMddHHmmss 문자열이다.
// LocalDateTime 을 그대로 바인딩하면 27자로 변환되어 ORA-12899(값 초과)가 발생하므로
// 14자 문자열로 변환하는 컨버터를 적용한다.
@Column(name = "password_change_date", length = 14)
@Convert(converter = com.eactive.eai.data.converter.LocalDateTimeToStringConverter14.class)
@Comment("비밀번호변경일시")
private LocalDateTime passwordChangeDate;
@@ -20,7 +20,8 @@ public class TwoFactorAuth {
@Id
@Column(name = "id", length = 36, nullable = false)
@GenericGenerator(name = "uuid-gen", strategy = "uuid2")
// UUID v7(타임스탬프 기반, 시간순 정렬) — PK 인덱스 삽입 지역성 개선. 기존 v4 행과 컬럼 호환.
@GenericGenerator(name = "uuid-gen", strategy = "com.eactive.apim.portal.jpa.UuidV7Generator")
@GeneratedValue(generator = "uuid-gen", strategy = GenerationType.IDENTITY)
private String id;
@@ -0,0 +1,76 @@
package com.eactive.apim.portal.portaluser.entity;
import com.eactive.eai.data.converter.LocalDateTimeToStringConverter14;
import lombok.Data;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 사용자 역할(권한) 변경 감사 이력.
*
* <p>법인 관리자 위임/회수, 소속 제외 등으로 {@code PortalUser.roleCode} 가 변경될 때
* 이전 역할 → 새 역할, 변경 유형, 변경 수행자(관리자)를 이력으로 남긴다.
* {@link UserPasswordHistory} 와 동일한 저장 패턴(시퀀스 PK, 14자리 문자열 일시)을 따른다.</p>
*/
@Data
@Entity
@Table(name = "ptl_user_role_history")
public class UserRoleHistory implements Serializable, com.eactive.eai.data.Data {
private static final long serialVersionUID = 1L;
@Id
@GenericGenerator(
name = "ptl_user_role_history_seq_gen",
strategy = "com.eactive.eai.rms.data.jpa.SchemaPrefixedSequenceGenerator",
parameters = {
@Parameter(name = "sequence_name", value = "PTL_USER_ROLE_HISTORY_SEQ"),
@Parameter(name = "initial_value", value = "1"),
@Parameter(name = "increment_size", value = "1")
}
)
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "ptl_user_role_history_seq_gen"
)
@Column(name = "id", columnDefinition = "number(19)")
private Long id;
@Column(name = "user_id", length = 255, nullable = false)
@Comment("대상 사용자 ID(loginId)")
private String userId;
@Column(name = "before_role", length = 30)
@Comment("변경 전 역할")
private String beforeRole;
@Column(name = "after_role", length = 30, nullable = false)
@Comment("변경 후 역할")
private String afterRole;
@Column(name = "change_type", length = 30, nullable = false)
@Comment("변경 유형(MANAGER_ASSIGN/MANAGER_REVOKE/ORG_REMOVE 등)")
private String changeType;
@Column(name = "changed_by", length = 255, nullable = false)
@Comment("변경 수행자(loginId)")
private String changedBy;
@Column(name = "change_date", length = 14, nullable = false)
@Comment("변경 일시")
@Convert(converter = LocalDateTimeToStringConverter14.class)
private LocalDateTime changeDate;
@Column(name = "created_by", length = 255, nullable = false)
@Comment("생성자")
private String createdBy;
@Column(name = "created_date", length = 14, nullable = false)
@Comment("생성일시")
@Convert(converter = LocalDateTimeToStringConverter14.class)
private LocalDateTime createdDate;
}
@@ -2,7 +2,9 @@ package com.eactive.apim.portal.portaluser.repository;
import com.eactive.apim.portal.portaluser.entity.TwoFactorAuth;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import java.time.LocalDateTime;
import java.util.Optional;
public interface TwoFactorAuthRepository extends JpaRepository<TwoFactorAuth, String> {
@@ -12,6 +14,14 @@ public interface TwoFactorAuthRepository extends JpaRepository<TwoFactorAuth, St
void deleteAllByRecipientKey(String recipientKey);
/**
* 만료된 인증번호 레코드를 일괄 삭제한다. (정리 스케줄러용)
* expires_on 은 LocalDateTimeToStringConverter14(yyyyMMddHHmmss) 로 저장되며,
* 해당 포맷은 사전식 정렬이 시간순과 일치하므로 문자열 &lt; 비교가 곧 시간 비교다.
*/
@Modifying
int deleteAllByExpiresAtBefore(LocalDateTime threshold);
// 아래 두 메서드는 recipient(암호화 컬럼) 기반이라 신뢰할 수 없음 — 신규 코드에서는 RecipientKey 버전을 사용할 것.
@Deprecated
Optional<TwoFactorAuth> findByRecipient(String recipientKey);
@@ -0,0 +1,13 @@
package com.eactive.apim.portal.portaluser.repository;
import com.eactive.apim.portal.portaluser.entity.UserRoleHistory;
import com.eactive.eai.rms.data.EMSDataSource;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
@EMSDataSource
public interface UserRoleHistoryRepository extends JpaRepository<UserRoleHistory, Long> {
List<UserRoleHistory> findByUserIdOrderByChangeDateDesc(String userId);
}
@@ -1,7 +1,37 @@
package com.eactive.apim.portal.portaluser.service;
public class AuthNumberException extends RuntimeException{
/**
* 인증번호(2FA/이메일/SMS) 검증·발송 실패 예외.
*
* <p>기존에는 메시지 문자열만 있었으나, 감사 로그에서 실패 사유(만료/불일치/미존재)를
* 코드로 구분해야 하므로 {@link Reason} 을 추가했다. 기존 메시지 전용 생성자는 유지되며
* 이 경우 {@code reason == null} 이다(하위호환).</p>
*/
public class AuthNumberException extends RuntimeException {
/** 실패 사유 분류 */
public enum Reason {
/** 저장된 인증번호가 없음(미발송/이미 소비/스케줄러 정리) */
NOT_FOUND,
/** 유효시간 초과 */
EXPIRED,
/** 인증번호 불일치 */
MISMATCH
}
private final Reason reason;
public AuthNumberException(String message) {
super(message);
this.reason = null;
}
public AuthNumberException(String message, Reason reason) {
super(message);
this.reason = reason;
}
public Reason getReason() {
return reason;
}
}
@@ -86,4 +86,23 @@ public class Inquiry extends Auditable {
@Column(name = "ATTACH_FILE")
private String attachFile;
/**
* 공개범위 (전체공개/법인공개/비공개). 기본값 ORG.
* PTL_PROPERTY 기관 기본값이 상한(ceiling)이며 읽기/쓰기 시 clamp 된다.
*/
@Enumerated(EnumType.STRING)
@Column(name = "VISIBILITY", length = 16)
private VisibilityScope visibility = VisibilityScope.ORG;
/**
* 조회수. sessionStorage 기반 dedup 후 POST 요청으로만 증가한다.
*/
@Column(name = "VIEW_COUNT")
private long viewCount = 0L;
/** 조회수 1 증가. */
public void increaseViewCount() {
this.viewCount++;
}
}
@@ -36,6 +36,18 @@ public class InquiryComment extends Auditable implements Serializable {
@Column(name = "ADMIN_YN", length = 1)
private String adminYn = "N";
/**
* 댓글 공개범위. 개념상 공개(ALL)/비공개(PRIVATE) 2단계.
* 비공개 댓글은 작성자·같은 법인 corp-manager·관리자만 열람 가능.
*/
@Enumerated(EnumType.STRING)
@Column(name = "VISIBILITY", length = 16)
private VisibilityScope visibility = VisibilityScope.ALL;
public boolean isPrivate() {
return this.visibility == VisibilityScope.PRIVATE;
}
public void markDeleted() {
this.delYn = "Y";
}
@@ -0,0 +1,67 @@
package com.eactive.apim.portal.qna.entity;
/**
* 문의(Q&amp;A) 게시물/댓글의 공개범위.
*
* <p>{@code width}는 공개 범위의 넓이 랭크로, 값이 클수록 더 넓게 공개된다.
* {@code PTL_PROPERTY}에 설정된 기관 기본값이 상한(ceiling)이 되며, 게시물이 상한보다
* 넓게 설정될 수 없다({@link #clampTo}). property가 항상 우선한다.</p>
*
* <ul>
* <li>{@code ALL} : 전체 로그인 사용자 공개</li>
* <li>{@code ORG} : 같은 법인 소속 사용자 공개 (게시물 기본값)</li>
* <li>{@code PRIVATE} : 작성자 본인만 (댓글의 "비공개")</li>
* </ul>
*/
public enum VisibilityScope {
ALL(3, "전체공개"),
ORG(2, "법인공개"),
PRIVATE(1, "비공개");
private final int width;
private final String label;
VisibilityScope(int width, String label) {
this.width = width;
this.label = label;
}
/** 공개 범위 넓이 랭크. 클수록 넓게 공개. */
public int width() {
return width;
}
/** 화면 표기용 한글 라벨. */
public String label() {
return label;
}
/**
* 문자열을 enum으로 안전 변환. null/빈값/미해당은 defaultScope 반환.
*/
public static VisibilityScope fromString(String value, VisibilityScope defaultScope) {
if (value == null || value.trim().isEmpty()) {
return defaultScope;
}
try {
return VisibilityScope.valueOf(value.trim().toUpperCase());
} catch (IllegalArgumentException e) {
return defaultScope;
}
}
/**
* 요청 공개범위를 상한으로 clamp 한다. 요청이 상한보다 넓으면 상한으로 낮춘다.
* (property가 항상 우선하므로, 저장값이 옛 상한이라 더 넓더라도 읽기 시 재-clamp 한다.)
*/
public static VisibilityScope clampTo(VisibilityScope requested, VisibilityScope ceiling) {
if (requested == null) {
return ceiling;
}
if (ceiling == null) {
return requested;
}
return requested.width() > ceiling.width() ? ceiling : requested;
}
}
@@ -1,6 +1,7 @@
package com.eactive.apim.portal.template.entity;
import com.eactive.apim.portal.common.util.PhoneNumberUtil;
import com.eactive.apim.portal.jpa.PersonalDataEncryptConverter;
import com.eactive.apim.portal.portaluser.entity.PortalUser;
import com.eactive.eai.data.converter.LocalDateTimeToStringConverter14;
@@ -83,4 +84,11 @@ public class MessageRequest implements Serializable {
@Column(name = "service_id")
private String serviceId;
/** 저장 시 전화번호를 하이픈 구분 정규형으로 통일 */
@PrePersist
@PreUpdate
private void normalizePhones() {
this.phone = PhoneNumberUtil.normalize(this.phone);
}
}
@@ -78,7 +78,7 @@ public class MessageSendService {
String subject = buildMessage(template.getSubjectTemplate(), messageParams);
if (template.getEnableSms().equalsIgnoreCase("Y")) {
String smsEaiInterfaceId = portalProperties.get("ums.sms.if_id");
String smsEaiInterfaceId = portalProperties.get("djb.ums.sms.if_id");
MessageRequest smsRequest = new MessageRequest();
smsRequest.setMessageCode(MessageCode.valueOf(template.getMessageCode().toUpperCase()));
smsRequest.setSubject(subject);
@@ -88,19 +88,15 @@ public class MessageSendService {
smsRequest.setUsername(user.getUsername());
smsRequest.setPhone(user.getPhone());
smsRequest.setEaiInterfaceId(smsEaiInterfaceId);
smsRequest.setServiceId(portalProperties.get("ums.sms.tx_id"));
smsRequest.setServiceId(portalProperties.get("djb.ums.sms.tx_id"));
smsRequest.setUserId(user.getUserId());
if ("ADMIN_VERIFICATION_MOBILEPHONE".equals(template.getMessageCode().toUpperCase())) {
smsRequest.setMessageType("KAKAO");
} else {
smsRequest.setMessageType("SMS");
}
smsRequest.setMessageType("KAKAO");
messageRequestRepository.save(smsRequest);
logger.debug(smsRequest.toString());
}
if (template.getEnableEmail().equalsIgnoreCase("Y")) {
String mailEaiInterfaceId = portalProperties.get("ums.email.if_id");
String mailEaiInterfaceId = portalProperties.get("djb.ums.email.if_id");
MessageRequest emailRequest = new MessageRequest();
emailRequest.setMessageCode(MessageCode.valueOf(template.getMessageCode().toUpperCase()));
emailRequest.setSubject(subject);
@@ -110,7 +106,7 @@ public class MessageSendService {
emailRequest.setUsername(user.getUsername());
emailRequest.setEmail(user.getUserId());
emailRequest.setEaiInterfaceId(mailEaiInterfaceId);
emailRequest.setServiceId(portalProperties.get("ums.email.tx_id"));
emailRequest.setServiceId(portalProperties.get("djb.ums.email.tx_id"));
emailRequest.setMessageType("EMAIL");
emailRequest.setUserId(user.getUserId());
messageRequestRepository.save(emailRequest);
@@ -118,7 +114,7 @@ public class MessageSendService {
}
if (template.getEnableMessenger().equalsIgnoreCase("Y")) {
String swingEaiInterfaceId = portalProperties.get("ums.messenger.if_id");
String swingEaiInterfaceId = portalProperties.get("djb.ums.messenger.if_id");
MessageRequest messengerRequest = new MessageRequest();
messengerRequest.setMessageCode(MessageCode.valueOf(template.getMessageCode()));
messengerRequest.setSubject(subject);
@@ -128,7 +124,7 @@ public class MessageSendService {
messengerRequest.setUsername(user.getUsername());
messengerRequest.setMessengerId(user.getUserId());
messengerRequest.setEaiInterfaceId(swingEaiInterfaceId);
messengerRequest.setServiceId(portalProperties.get("ums.messenger.tx_id"));
messengerRequest.setServiceId(portalProperties.get("djb.ums.messenger.tx_id"));
messengerRequest.setMessageType("MESSENGER");
messengerRequest.setUserId(user.getUserId());
messageRequestRepository.save(messengerRequest);
@@ -11,6 +11,7 @@ import lombok.NonNull;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Comment;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import javax.persistence.*;
@@ -73,6 +74,12 @@ public class UserInfo extends AbstractEntity<String> implements Serializable {
@LastModifiedDate
private LocalDateTime lastamndyms;
@Column(length = 14)
@Comment("등록 일시")
@Convert(converter = LocalDateTimeToStringConverter14.class)
@CreatedDate
private LocalDateTime regdyms;
@Column(length = 80)
@Comment("부서명")
private String dvsnname;
@@ -133,9 +140,13 @@ public class UserInfo extends AbstractEntity<String> implements Serializable {
private String allowip;
@Column(length = 1)
@Comment("사용자 계정 상태")
@Comment("사용자 계정 상태")
private String status;
@Column
@Comment("로그인 실패 횟수")
private Integer loginfailcount;
@Override
public @NonNull String getId() {
return userid;
@@ -45,4 +45,12 @@ public class UserLog {
@Column(name = "success", nullable = false)
private boolean success;
/** 실패 사유 코드 (LoginFailureReason). 성공 행은 null */
@Column(name = "failure_reason", length = 64)
private String failureReason;
/** 로그인 유형 코드 (LoginType: NORMAL/TWO_FACTOR/SIGNUP_AUTO). 실패 행·과거 행은 null */
@Column(name = "login_type", length = 32)
private String loginType;
}