- UserRoleHistoryService 추가: 역할 변경 감사 이력 서비스 구현
- `ROLE_API_KEY_REQUEST` → `ROLE_WEBHOOK` 변경: Webhook 관리 권한 분리 및 강화 - "이용자" → "개발자" 용어 통일: 템플릿, 컨트롤러 및 예외 메시지 수정
This commit is contained in:
@@ -224,12 +224,15 @@ portal:
|
||||
- ROLE_INQUIRY
|
||||
- ROLE_ACCOUNT
|
||||
ROLE_CORP_USER:
|
||||
- ROLE_API_KEY_REQUEST
|
||||
- ROLE_API_KEY_REQUEST_VIEW
|
||||
- ROLE_INQUIRY
|
||||
- ROLE_APP
|
||||
- ROLE_ACCOUNT
|
||||
ROLE_CORP_MANAGER:
|
||||
- ROLE_API_KEY_REQUEST
|
||||
- ROLE_API_KEY_REQUEST_VIEW
|
||||
- ROLE_WEBHOOK
|
||||
- ROLE_INQUIRY
|
||||
- ROLE_APP
|
||||
- ROLE_ACCOUNT
|
||||
@@ -355,10 +358,10 @@ page:
|
||||
name: "이메일 인증"
|
||||
path: "/mypage/verification-email"
|
||||
user_list:
|
||||
name: "이용자 관리"
|
||||
name: "개발자 관리"
|
||||
path: "/users"
|
||||
user_detail:
|
||||
name: "이용자 정보"
|
||||
name: "개발자 정보"
|
||||
path: "/users/detail"
|
||||
apikey:
|
||||
name: "앱 관리"
|
||||
|
||||
@@ -82,6 +82,6 @@ status=Status
|
||||
table.reger=Registrar
|
||||
zip=Zip Code
|
||||
ROLE_CORP_MANAGER=Manager
|
||||
ROLE_CORP_USER=User
|
||||
ROLE_CORP_USER=Developer
|
||||
ROLE_USER=Individual
|
||||
login.passLengthShort=Password must be over 8 characters.
|
||||
|
||||
@@ -82,6 +82,6 @@ status=\uC0C1\uD0DC
|
||||
table.reger=\uB4F1\uB85D\uC790
|
||||
zip=\uC6B0\uD3B8\uBC88\uD638
|
||||
ROLE_CORP_MANAGER=\uAD00\uB9AC\uC790
|
||||
ROLE_CORP_USER=\uC774\uC6A9\uC790
|
||||
ROLE_CORP_USER=\uAC1C\uBC1C\uC790
|
||||
ROLE_USER=\uAC1C\uC778\uC0AC\uC6A9\uC790
|
||||
ConcurrentSessionControlAuthenticationStrategy.exceededAllowed=\uCD5C\uB300 \uB85C\uADF8\uC778 \uD5C8\uC6A9 \uC5F0\uACB0\uC744 \uCD08\uACFC\uD558\uC600\uC2B5\uB2C8\uB2E4.
|
||||
|
||||
@@ -27,6 +27,10 @@
|
||||
<i class="fas fa-info-circle"></i>
|
||||
<span>다른 기기 또는 브라우저에서 로그인되어 현재 세션이 종료되었습니다.</span>
|
||||
</div>
|
||||
<div th:if="${param.reason == 'auth'}" class="login-alert alert-info">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
<span>인증된 사용자만 접근 가능한 페이지입니다. 로그인 후 이용해 주세요.</span>
|
||||
</div>
|
||||
|
||||
<!-- Login Form -->
|
||||
<form id="loginForm" role="form" name="loginForm" th:action="@{/actionLogin.do}" method="post" class="login-form">
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
<div class="org-info-notice">
|
||||
<ul>
|
||||
<li>법인 관리자는 API 신청 및 이용자 초대 등 모든 권한을 보유합니다.</li>
|
||||
<li>법인 관리자는 API 신청 및 개발자 초대 등 모든 권한을 보유합니다.</li>
|
||||
<li>법인회원 전환은 반드시 법인이메일 주소로 입력하시기 바랍니다. 개인이메일로 전환 신청시, 법인 승인이 거절 될 수 있습니다</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
|
||||
<div class="org-info-notice">
|
||||
<ul>
|
||||
<li>법인관리자는 API 신청 및 이용자 초대 등 모든 권한을 보유합니다.</li>
|
||||
<li>법인관리자는 API 신청 및 개발자 초대 등 모든 권한을 보유합니다.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
<section layout:fragment="title">
|
||||
<div class="page-title-banner">
|
||||
<img th:src="@{/img/img_title_bg.png}" class="title-image">
|
||||
<h1>이용자 관리</h1>
|
||||
<h1>개발자 관리</h1>
|
||||
</div>
|
||||
</section>
|
||||
<section layout:fragment="contentFragment">
|
||||
<div class="org-register-container">
|
||||
|
||||
<div class="common-title-bar">
|
||||
<h2 class="common-title">이용자 정보</h2>
|
||||
<h2 class="common-title">개발자 정보</h2>
|
||||
</div>
|
||||
|
||||
<div class="register-form-container">
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<div class="search-box">
|
||||
<button type="button" class="btn btn-primary" id="addUserBtn">
|
||||
<i class="fas fa-plus"></i>
|
||||
<span>이용자 추가</span>
|
||||
<span>개발자 추가</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -78,7 +78,7 @@
|
||||
th:if="${user.userStatus.toString() == 'ACTIVE' && user.roleCode.toString() == 'ROLE_CORP_MANAGER'}"
|
||||
th:data-user-id="${user.id}"
|
||||
th:data-user-name="${user.maskedUserName}">
|
||||
이용자로 변경
|
||||
개발자로 변경
|
||||
</button>
|
||||
<button type="button" class="list-table-btn list-table-btn--danger remove_from_org"
|
||||
th:if="${user.userStatus.toString() == 'ACTIVE' && (user.roleCode.toString() == 'ROLE_CORP_USER' || user.roleCode.toString() == 'ROLE_CORP_MANAGER')}"
|
||||
@@ -121,7 +121,7 @@
|
||||
th:if="${user.userStatus.toString() == 'ACTIVE' && user.roleCode.toString() == 'ROLE_CORP_MANAGER'}"
|
||||
th:data-user-id="${user.id}"
|
||||
th:data-user-name="${user.maskedUserName}">
|
||||
이용자로 변경
|
||||
개발자로 변경
|
||||
</button>
|
||||
<button type="button" class="dropdown-item dropdown-item--danger remove_from_org"
|
||||
th:if="${user.userStatus.toString() == 'ACTIVE' && (user.roleCode.toString() == 'ROLE_CORP_USER' || user.roleCode.toString() == 'ROLE_CORP_MANAGER')}"
|
||||
@@ -155,7 +155,7 @@
|
||||
<div class="row-cell" data-label="휴대폰" th:text="${user.maskedMobileNumber}">
|
||||
010-****-****
|
||||
</div>
|
||||
<div class="row-cell" data-label="권한">이용자</div>
|
||||
<div class="row-cell" data-label="권한">개발자</div>
|
||||
<div class="row-cell" data-label="계정상태">초대중</div>
|
||||
<div class="row-cell row-actions">
|
||||
<!-- Desktop -->
|
||||
@@ -193,8 +193,8 @@
|
||||
<!-- Empty State -->
|
||||
<div class="user-empty-state" th:if="${(users == null or users.isEmpty()) and (pendingUsers == null or pendingUsers.isEmpty())}">
|
||||
<div class="empty-icon">👥</div>
|
||||
<h3>등록된 이용자가 없습니다</h3>
|
||||
<p>새로운 이용자를 추가하여 시작하세요.</p>
|
||||
<h3>등록된 개발자가 없습니다</h3>
|
||||
<p>새로운 개발자를 추가하여 시작하세요.</p>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
@@ -281,9 +281,9 @@
|
||||
let errorMessage;
|
||||
try {
|
||||
const errorResponse = JSON.parse(jqXHR.responseText);
|
||||
errorMessage = errorResponse.msg || '이용자 초대 중 오류가 발생했습니다';
|
||||
errorMessage = errorResponse.msg || '개발자 초대 중 오류가 발생했습니다';
|
||||
} catch (e) {
|
||||
errorMessage = '이용자 초대 중 오류가 발생했습니다: ' + errorThrown;
|
||||
errorMessage = '개발자 초대 중 오류가 발생했습니다: ' + errorThrown;
|
||||
}
|
||||
customPopups.showUserInviteError(errorMessage);
|
||||
});
|
||||
@@ -294,7 +294,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
// Add event listeners to the "이용자 추가" buttons
|
||||
// Add event listeners to the "개발자 추가" buttons
|
||||
const addUserBtn = document.getElementById('addUserBtn');
|
||||
|
||||
if (addUserBtn) {
|
||||
@@ -334,14 +334,14 @@
|
||||
});
|
||||
});
|
||||
|
||||
// 관리자 -> 이용자 변경 (본인 제외)
|
||||
// 관리자 -> 개발자 변경 (본인 제외)
|
||||
document.querySelectorAll('.revoke_manager').forEach(button => {
|
||||
button.addEventListener('click', function(event) {
|
||||
const btn = event.currentTarget;
|
||||
const userId = btn.dataset.userId;
|
||||
const userName = btn.dataset.userName;
|
||||
|
||||
customPopups.showConfirm(`<strong>${userName}</strong>님을 이용자로 변경하시겠습니까?`, function(selection) {
|
||||
customPopups.showConfirm(`<strong>${userName}</strong>님을 개발자로 변경하시겠습니까?`, function(selection) {
|
||||
if (!selection) return;
|
||||
$.ajax({
|
||||
url: '/users/revoke-manager',
|
||||
|
||||
@@ -33,14 +33,14 @@
|
||||
<h3>등록된 Webhook이 없습니다</h3>
|
||||
<p>API 서비스의 점검·지연·장애 알림을 받을 Webhook을 신청해보세요.</p>
|
||||
|
||||
<p class="field-help" sec:authorize="!hasRole('ROLE_API_KEY_REQUEST')">
|
||||
<p class="field-help" sec:authorize="!hasRole('ROLE_WEBHOOK')">
|
||||
Webhook 신청은 법인 관리자만 가능합니다. 기관 관리자에게 문의하세요.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 액션 -->
|
||||
<div class="s1-actions" sec:authorize="hasRole('ROLE_API_KEY_REQUEST')">
|
||||
<div class="s1-actions" sec:authorize="hasRole('ROLE_WEBHOOK')">
|
||||
<button type="button" class="s1-btn-next" id="requestWebhook">Webhook 신청</button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
<span class="group-label">Secret Key</span>
|
||||
<div class="secret-action-row">
|
||||
<div class="secret-box" id="secretMasked" th:text="*{secretMasked}">************</div>
|
||||
<th:block sec:authorize="hasRole('ROLE_API_KEY_REQUEST')">
|
||||
<th:block sec:authorize="hasRole('ROLE_WEBHOOK')">
|
||||
<button type="button" class="btn-reveal-action" id="btnRevealSecret">조회</button>
|
||||
<button type="button" class="btn-regen-action" id="btnRegenSecret">재발급</button>
|
||||
</th:block>
|
||||
@@ -91,7 +91,7 @@
|
||||
</div>
|
||||
|
||||
<!-- 액션 -->
|
||||
<div class="s1-actions" sec:authorize="hasRole('ROLE_API_KEY_REQUEST')">
|
||||
<div class="s1-actions" sec:authorize="hasRole('ROLE_WEBHOOK')">
|
||||
<button type="button" class="btn-webhook-danger-figma" id="btnDeleteWebhook">삭제</button>
|
||||
<a class="s1-btn-next-figma" th:href="@{/webhook/modify/step1}">수정</a>
|
||||
</div>
|
||||
|
||||
@@ -88,12 +88,12 @@
|
||||
<button class="header-link mypage-toggle" type="button">마이페이지</button>
|
||||
<div class="mypage-dropdown-menu">
|
||||
<ul class="mypage-menu-list">
|
||||
<li sec:authorize="hasRole('ROLE_USER_MANAGER')">
|
||||
<a th:href="@{/users}"><i class="fas fa-users"></i>이용자 관리</a>
|
||||
<li sec:authorize="hasRole('ROLE_CORP_MANAGER')">
|
||||
<a th:href="@{/users}"><i class="fas fa-users"></i>개발자 관리</a>
|
||||
</li>
|
||||
<li sec:authorize="hasRole('ROLE_APP')">
|
||||
<a th:href="@{/myapikey}"><i class="fas fa-key"></i>앱 관리</a>
|
||||
<a th:href="@{/webhook}" sec:authorize="hasRole('ROLE_API_KEY_REQUEST')"><i class="fas fa-bell"></i>Webhook 관리</a>
|
||||
<a th:href="@{/webhook}" sec:authorize="hasRole('ROLE_WEBHOOK')"><i class="fas fa-bell"></i>Webhook 관리</a>
|
||||
<a th:href="@{/statistics/api}"><i class="fas fa-chart-bar"></i>이용 통계</a>
|
||||
</li>
|
||||
<li><a th:href="@{/mypage}"><i class="fas fa-user-circle"></i>내 정보 관리</a></li>
|
||||
@@ -248,9 +248,9 @@
|
||||
</svg>
|
||||
</button>
|
||||
<ul class="drawer-submenu">
|
||||
<li sec:authorize="hasRole('ROLE_USER_MANAGER')"><a th:href="@{/users}">이용자 관리</a></li>
|
||||
<li sec:authorize="hasRole('ROLE_CORP_MANAGER')"><a th:href="@{/users}">개발자 관리</a></li>
|
||||
<li sec:authorize="hasRole('ROLE_APP')"><a th:href="@{/myapikey}">앱 관리</a></li>
|
||||
<li sec:authorize="hasRole('ROLE_API_KEY_REQUEST')"><a th:href="@{/webhook}">Webhook 관리</a></li>
|
||||
<li sec:authorize="hasRole('ROLE_WEBHOOK')"><a th:href="@{/webhook}">Webhook 관리</a></li>
|
||||
<li sec:authorize="hasRole('ROLE_APP')"><a th:href="@{/statistics/api}">이용 통계</a></li>
|
||||
<li><a th:href="@{/mypage}">내 정보 관리</a></li>
|
||||
<li><a th:href="@{/password/verify}">비밀번호 변경</a></li>
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<a th:href="@{/users}"
|
||||
th:classappend="${activeMenu == 'users'} ? 'service-nav__item--active' : ''"
|
||||
class="service-nav__item"
|
||||
sec:authorize="hasRole('ROLE_CORP_MANAGER')">이용자 관리</a>
|
||||
sec:authorize="hasRole('ROLE_CORP_MANAGER')">개발자 관리</a>
|
||||
|
||||
<a th:href="@{/myapikey}"
|
||||
th:classappend="${activeMenu == 'apiKey'} ? 'service-nav__item--active' : ''"
|
||||
@@ -62,7 +62,7 @@
|
||||
<a th:href="@{/webhook}"
|
||||
th:classappend="${activeMenu == 'webhook'} ? 'service-nav__item--active' : ''"
|
||||
class="service-nav__item"
|
||||
sec:authorize="hasRole('ROLE_API_KEY_REQUEST')">Webhook 관리</a>
|
||||
sec:authorize="hasRole('ROLE_WEBHOOK')">Webhook 관리</a>
|
||||
|
||||
<a th:href="@{/statistics/api}"
|
||||
th:classappend="${activeMenu == 'statistics'} ? 'service-nav__item--active' : ''"
|
||||
|
||||
@@ -21,19 +21,6 @@
|
||||
</script>
|
||||
</section>
|
||||
|
||||
<section sec:authorize="hasAuthority('ROLE_CORP_USER')" class="content pop" th:fragment="apiKeyRequestPopup">
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
(function($) {
|
||||
$('#requestApiKey').on('click', function(event) {
|
||||
event.preventDefault();
|
||||
customPopups.showAlert('법인 관리자만 신청 가능합니다.');
|
||||
});
|
||||
})(jQuery);
|
||||
});
|
||||
</script>
|
||||
</section>
|
||||
|
||||
<section class="content pop" th:fragment="apiKeyRequestPopup" th:if="${#authorization.expression('!isAuthenticated()')}">
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<!-- Modal Header -->
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">이용자 추가</h3>
|
||||
<h3 class="modal-title">개발자 추가</h3>
|
||||
<button type="button" class="modal-close" id="userInvitePopupCloseButton">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="18" y1="6" x2="6" y2="18"></line>
|
||||
@@ -21,7 +21,7 @@
|
||||
<!-- Modal Body -->
|
||||
<div class="modal-body">
|
||||
<p id="userInvitePopupMessage" style="text-align: center; margin-bottom: 24px; color: #64748B;">
|
||||
추가할 이용자 휴대폰 번호를 입력해 주세요.
|
||||
추가할 개발자 휴대폰 번호를 입력해 주세요.
|
||||
</p>
|
||||
|
||||
<!-- Mobile Input Field -->
|
||||
|
||||
Reference in New Issue
Block a user