Browse Source

changes in UI changes credentials showing

master
yoga-agoy 3 months ago
parent
commit
0625a9a698
  1. 14
      src/main/java/com/gcc_it_cell_services/springboot/controller/HomeController.java
  2. 18
      src/main/java/com/gcc_it_cell_services/springboot/controller/UrlDataController.java
  3. 3
      src/main/java/com/gcc_it_cell_services/springboot/rest_controller/HomeRestController.java
  4. 17
      src/main/resources/static/assets/js/home-script.js
  5. 49
      src/main/resources/templates/fragments/navbar.html
  6. 4
      src/main/resources/templates/home/home.html
  7. 2
      src/main/resources/templates/urls/add-url-data.html
  8. 125
      src/main/resources/templates/urls/get-urls-by-url-category.html
  9. 2
      src/main/resources/templates/urls/update-url-data.html

14
src/main/java/com/gcc_it_cell_services/springboot/controller/HomeController.java

@ -24,12 +24,18 @@ public class HomeController {
private UrlDataService urlDataSer;
@GetMapping({ "/", "" })
public String home(Model model, Authentication auth) {
public String home(Model model, Authentication auth, javax.servlet.http.HttpServletRequest req) {
List<UrlDataResponseDTO> urls = urlDataSer.getAllUrls();
// Add role information to the model for conditional navbar rendering
boolean isAdmin = auth != null
&& auth.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN"));
javax.servlet.http.HttpSession session = req.getSession(false);
boolean isOtpVerified = session != null && session.getAttribute("otpVerified") != null && (Boolean) session.getAttribute("otpVerified");
boolean isLoggedIn = (auth != null && auth.isAuthenticated() && !auth.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ROLE_ANONYMOUS"))) || isOtpVerified;
model.addAttribute("isAdmin", isAdmin);
model.addAttribute("isLoggedIn", isLoggedIn);
model.addAttribute("curPage", "home");
model.addAttribute("urls", urls);
return "home/home";
@ -45,7 +51,13 @@ public class HomeController {
// Add role information to the model for conditional navbar rendering
boolean isAdmin = auth != null
&& auth.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN"));
if (!isAdmin) {
return "redirect:/"; // Redirect to home if not admin
}
model.addAttribute("isAdmin", isAdmin);
model.addAttribute("isLoggedIn", true);
List<UrlDataResponseDTO> urls = urlDataSer.getAllUrlsWithUsrNameAndPass();
model.addAttribute("urls", urls);
model.addAttribute("curPage", "view-login-det");

18
src/main/java/com/gcc_it_cell_services/springboot/controller/UrlDataController.java

@ -27,12 +27,13 @@ public class UrlDataController {
boolean isAdmin = auth != null
&& auth.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN"));
model.addAttribute("isAdmin", isAdmin);
model.addAttribute("isLoggedIn", isAdmin);
model.addAttribute("curPage", "add-url");
return "urls/add-url-data";
}
@GetMapping("/get-{urlCatName}-urls")
public String getUrlsByCategory(@PathVariable("urlCatName") String urlCatName, Model model, Authentication auth) {
public String getUrlsByCategory(@PathVariable("urlCatName") String urlCatName, Model model, Authentication auth, javax.servlet.http.HttpServletRequest req) {
// Add role information to the model for conditional navbar rendering
urlCatName = urlCatName.replace("-", " ");
List<UrlDataResponseDTO> urls = urlDataSer.getUrlsByUrlCatName(urlCatName);
@ -49,7 +50,21 @@ public class UrlDataController {
boolean isAdmin = auth != null
&& auth.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN"));
// Check if user is logged in (either via Spring Security authentication or session OTP verification)
javax.servlet.http.HttpSession session = req.getSession(false);
boolean isOtpVerified = session != null && session.getAttribute("otpVerified") != null && (Boolean) session.getAttribute("otpVerified");
boolean isLoggedIn = (auth != null && auth.isAuthenticated() && !auth.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ROLE_ANONYMOUS"))) || isOtpVerified;
// Filter urls that actually have a username and password
List<UrlDataResponseDTO> credentialUrls = urls.stream()
.filter(dto -> dto.getUrlDataUsrName() != null && !dto.getUrlDataUsrName().trim().equals("-")
&& dto.getUrlDataUsrPass() != null && !dto.getUrlDataUsrPass().trim().equals("-"))
.collect(java.util.stream.Collectors.toList());
model.addAttribute("isAdmin", isAdmin);
model.addAttribute("isLoggedIn", isLoggedIn);
model.addAttribute("credentialUrls", credentialUrls);
model.addAttribute("urlCatName", resolvedCatName);
model.addAttribute("groupedUrls", groupedUrls);
model.addAttribute("urls", urls);
@ -64,6 +79,7 @@ public class UrlDataController {
boolean isAdmin = auth != null
&& auth.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN"));
model.addAttribute("isAdmin", isAdmin);
model.addAttribute("isLoggedIn", isAdmin);
model.addAttribute("curPage", "upd-url");
model.addAttribute("stats", stats);
model.addAttribute("urls", urls);

3
src/main/java/com/gcc_it_cell_services/springboot/rest_controller/HomeRestController.java

@ -66,11 +66,12 @@ public class HomeRestController {
HttpSession ses = req.getSession(false);
ServiceResponseDTO serResDTO = homeSer.verifyOtp(verifyOtpReqDTO, ses);
if (serResDTO.isResStat()) {
// OTP verified successfully → cleanup session
// OTP verified successfully → cleanup session and set otpVerified = true
ses.removeAttribute("otp");
ses.removeAttribute("otpTimestamp");
ses.removeAttribute("mobNum");
ses.removeAttribute("otpLogId");
ses.setAttribute("otpVerified", true);
return ResponseEntity.ok(serResDTO);
} else {
// OTP failed → remove old OTP only

17
src/main/resources/static/assets/js/home-script.js

@ -271,12 +271,11 @@ document.addEventListener("DOMContentLoaded", () => {
await reloadMobileDropdown();
// Close modal, then redirect to view-login-det
// Close modal, then reload the page
setTimeout(() => {
closeLoginModal();
window.open(`${contextPath}view-login-det`, '_blank');
window.location.reload();
}, 500);
} else {
// OTP verification failed or session expired
messageEl.textContent = data.res || "OTP verification failed. Please request a new one.";
@ -397,6 +396,10 @@ document.addEventListener("DOMContentLoaded", function () {
btn.style.display = "none";
}
});
if (typeof window.updateDropdownCredentials === "function") {
window.updateDropdownCredentials();
}
}
function showState2(subcatName) {
@ -431,6 +434,10 @@ document.addEventListener("DOMContentLoaded", function () {
btn.style.display = "none";
}
});
if (typeof window.updateDropdownCredentials === "function") {
window.updateDropdownCredentials();
}
}
/* === FILTER BUTTONS === */
@ -480,6 +487,10 @@ document.addEventListener("DOMContentLoaded", function () {
clearBtn.style.display = "none";
populateAlphabetDropdown(false);
}
if (typeof window.updateDropdownCredentials === "function") {
window.updateDropdownCredentials();
}
}
/* === CLICK HANDLERS === */

49
src/main/resources/templates/fragments/navbar.html

@ -1,4 +1,4 @@
<th:block th:fragment="navbar(curPage, isAdmin)">
<th:block th:fragment="navbar(curPage, isAdmin, isLoggedIn)">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<!-- Use container-fluid for full-width navbar -->
@ -22,44 +22,35 @@
th:if="${curPage != 'add-url'}"> <i class="fa-solid fa-circle-plus"></i>
Add URL
</a></li>
<!--<li class="nav-item"><a class="nav-link" th:href="@{/itcell/urls/add-url-data}"
th:if="${curPage != 'add-url'}"> <i class="fa-solid fa-circle-plus"></i>
Add URL 2
</a></li>-->
<li class="nav-item"><a class="nav-link" th:href="@{/urls/upd-url-data}"
th:if="${curPage != 'upd-url'}"> <i class="fa-solid fa-file-pen"></i>
Update URL
</a></li>
</th:block>
<li class="nav-item">
<a class="nav-link" href="#" onclick="openLoginModal(); return false;"
th:if="${curPage != 'view-login-det'}">
<li class="nav-item" th:if="${!isLoggedIn && curPage != 'view-login-det'}">
<a class="nav-link" href="#" onclick="openLoginModal(); return false;">
<i class="fa-solid fa-eye"></i> View Login Details
</a>
</li>
</ul>
<!--Navigation item on the right-->
<!-- Admin-only links, visible only if isAdmin is true -->
<th:block th:if="${isAdmin}">
<ul class=" navbar-nav ms-auto" th:if="${curPage == 'home'}">
<li class=" nav-item">
<form th:action="@{/usr-logout}" method="post" class="m-0 p-0">
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
<button type="submit" class="dropdown-item">
<i class="fa-solid fa-right-from-bracket"></i> Logout
</button>
</form>
</li>
</ul>
</th:block>
<th:block th:unless="${isAdmin}">
<ul class="navbar-nav ms-auto" th:if="${curPage == 'home'}">
<li class="nav-item"><a class="nav-link" th:href="@{/login}" th:if="${curPage == 'home'}"> <i
class="fa-solid fa-right-to-bracket"></i>
Login
</a></li>
</ul>
</th:block>
<ul class="navbar-nav ms-auto">
<!-- If user is logged in (either admin or OTP verified) → show Logout -->
<li class="nav-item" th:if="${isLoggedIn}">
<form th:action="@{/usr-logout}" method="post" class="m-0 p-0">
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
<button type="submit" class="nav-link btn btn-link" style="border: none; background: none; display: flex; align-items: center; gap: 5px; text-decoration: none;">
<i class="fa-solid fa-right-from-bracket"></i> Logout
</button>
</form>
</li>
<!-- If user is NOT logged in → show Login (Admin Login) -->
<li class="nav-item" th:if="${!isLoggedIn && curPage == 'home'}">
<a class="nav-link" th:href="@{/login}">
<i class="fa-solid fa-right-to-bracket"></i> Login
</a>
</li>
</ul>
</div>
</div>
</nav>

4
src/main/resources/templates/home/home.html

@ -21,7 +21,7 @@
<body>
<!-- Navigation -->
<th:block th:replace="~{fragments/navbar :: navbar(curPage=${curPage}, isAdmin=${isAdmin})}"></th:block>
<th:block th:replace="~{fragments/navbar :: navbar(curPage=${curPage}, isAdmin=${isAdmin}, isLoggedIn=${isLoggedIn})}"></th:block>
<div class="container">
<div class="form-container">
@ -52,7 +52,7 @@
? 'window.location.href=this.dataset.link'
: 'window.open(this.dataset.link, \'_blank\')'" class="custom-button">
<span class="url-num-badge">[[${url.urlDataNum}]]</span>
<!-- <span class="url-num-badge">[[${url.urlDataNum}]]</span> -->
[[${url.urlDataName}]]
</button>
</div>

2
src/main/resources/templates/urls/add-url-data.html

@ -21,7 +21,7 @@
<body>
<!-- Navigation -->
<th:block th:replace="~{fragments/navbar :: navbar(curPage=${curPage}, isAdmin=${isAdmin})}"></th:block>
<th:block th:replace="~{fragments/navbar :: navbar(curPage=${curPage}, isAdmin=${isAdmin}, isLoggedIn=${isLoggedIn})}"></th:block>
<div class="container">
<div class="form-container">

125
src/main/resources/templates/urls/get-urls-by-url-category.html

@ -20,20 +20,66 @@
<body>
<!-- Navigation -->
<th:block th:replace="~{fragments/navbar :: navbar(curPage=${curPage}, isAdmin=${isAdmin})}"></th:block>
<th:block th:replace="~{fragments/navbar :: navbar(curPage=${curPage}, isAdmin=${isAdmin}, isLoggedIn=${isLoggedIn})}"></th:block>
<div class="container">
<div class="form-container">
<!-- Back Button to Home (State 1) -->
<div class="header-row" id="category-back-row">
<div class="header-row" id="category-back-row" style="justify-content: space-between; width: 100%;">
<button type="button" class="back-button" onclick="window.history.back()">&#8592; Back</button>
<!-- CREDENTIALS SECTION (Top Right) -->
<div th:if="${isLoggedIn && credentialUrls != null && !credentialUrls.isEmpty()}" class="dropdown credentials-dropdown">
<button class="back-button dropdown-toggle" type="button" id="credentialsMenuButton" data-bs-toggle="dropdown" aria-expanded="false" style="margin-left: auto;">
<i class="fa-solid fa-key" style="margin-right: 5px;"></i> View Credentials
</button>
<ul class="dropdown-menu dropdown-menu-end p-3" aria-labelledby="credentialsMenuButton" style="min-width: 320px; max-height: 400px; overflow-y: auto; box-shadow: 0 10px 25px rgba(0,0,0,0.15); border-radius: 8px; border: 1px solid rgba(0,0,0,0.1);">
<h6 class="dropdown-header text-center" style="font-weight: bold; color: #003366; font-size: 1rem; border-bottom: 2px solid #005f73; padding-bottom: 8px; margin-bottom: 10px; text-decoration: none;">Page Credentials</h6>
<li th:each="cUrl : ${credentialUrls}" class="credential-item" th:data-url-name="${cUrl.urlDataName}" style="margin-bottom: 12px; border-bottom: 1px solid #eee; padding-bottom: 8px;">
<div style="font-weight: bold; color: #005f73; font-size: 0.95rem; margin-bottom: 4px;" th:text="${cUrl.urlDataName}">URL Name</div>
<div style="font-size: 0.85rem; color: #555; margin-bottom: 2px;">
<strong>Username:</strong> <span th:text="${cUrl.urlDataUsrName}" style="font-family: monospace; font-size: 0.9rem;">user</span>
</div>
<div style="font-size: 0.85rem; color: #555; display: flex; align-items: center; justify-content: space-between;">
<div>
<strong>Password:</strong>
<span th:id="'cat-pass-' + ${cUrl.urlDataId}" th:text="${'*'.repeat(cUrl.urlDataUsrPass?.length() ?: 0)}" style="font-family: monospace; font-size: 0.9rem;">pass</span>
</div>
<i class="fa-solid fa-eye toggle-cat-pass" th:attr="data-target='cat-pass-' + ${cUrl.urlDataId}, data-pass=${cUrl.urlDataUsrPass}" style="cursor: pointer; margin-left: 8px; color: #005f73; font-size: 1rem;"></i>
</div>
</li>
</ul>
</div>
</div>
<!-- Back Button to Subcategories (State 2) -->
<div class="header-row" id="subcat-back-row" style="display: none;">
<div class="header-row" id="subcat-back-row" style="display: none; justify-content: space-between; width: 100%;">
<button type="button" id="back-to-subcats-btn" class="back-button">
&#8592; Back
</button>
<!-- CREDENTIALS SECTION (Top Right) -->
<div th:if="${isLoggedIn && credentialUrls != null && !credentialUrls.isEmpty()}" class="dropdown credentials-dropdown">
<button class="back-button dropdown-toggle" type="button" id="credentialsMenuButtonSub" data-bs-toggle="dropdown" aria-expanded="false" style="margin-left: auto;">
<i class="fa-solid fa-key" style="margin-right: 5px;"></i> View Credentials
</button>
<ul class="dropdown-menu dropdown-menu-end p-3" aria-labelledby="credentialsMenuButtonSub" style="min-width: 320px; max-height: 400px; overflow-y: auto; box-shadow: 0 10px 25px rgba(0,0,0,0.15); border-radius: 8px; border: 1px solid rgba(0,0,0,0.1);">
<h6 class="dropdown-header text-center" style="font-weight: bold; color: #003366; font-size: 1rem; border-bottom: 2px solid #005f73; padding-bottom: 8px; margin-bottom: 10px; text-decoration: none;">Page Credentials</h6>
<li th:each="cUrl : ${credentialUrls}" class="credential-item" th:data-url-name="${cUrl.urlDataName}" style="margin-bottom: 12px; border-bottom: 1px solid #eee; padding-bottom: 8px;">
<div style="font-weight: bold; color: #005f73; font-size: 0.95rem; margin-bottom: 4px;" th:text="${cUrl.urlDataName}">URL Name</div>
<div style="font-size: 0.85rem; color: #555; margin-bottom: 2px;">
<strong>Username:</strong> <span th:text="${cUrl.urlDataUsrName}" style="font-family: monospace; font-size: 0.9rem;">user</span>
</div>
<div style="font-size: 0.85rem; color: #555; display: flex; align-items: center; justify-content: space-between;">
<div>
<strong>Password:</strong>
<span th:id="'cat-pass-sub-' + ${cUrl.urlDataId}" th:text="${'*'.repeat(cUrl.urlDataUsrPass?.length() ?: 0)}" style="font-family: monospace; font-size: 0.9rem;">pass</span>
</div>
<i class="fa-solid fa-eye toggle-cat-pass" th:attr="data-target='cat-pass-sub-' + ${cUrl.urlDataId}, data-pass=${cUrl.urlDataUsrPass}" style="cursor: pointer; margin-left: 8px; color: #005f73; font-size: 1rem;"></i>
</div>
</li>
</ul>
</div>
</div>
<!-- Heading + Search Bar on same line -->
@ -65,11 +111,11 @@
<th:block th:each="entry : ${groupedUrls}" th:if="${entry.key == '-'}">
<button type="button" th:each="url : ${entry.value}" th:attr="data-link = ${url.urlDataLink.startsWith('/urls')}
? @{${url.urlDataLink}}
: ${url.urlDataLink}" th:onclick="${url.urlDataLink.startsWith('/urls')}
: ${url.urlDataLink}, data-url-name = ${url.urlDataName}" th:onclick="${url.urlDataLink.startsWith('/urls')}
? 'window.location.href=this.dataset.link'
: 'window.open(this.dataset.link, \'_blank\')'" class="custom-button url-service-btn direct-url-btn"
data-subcat="-">
<span class="url-num-badge">[[${url.urlDataNum}]]</span>
data-subcat="-" th:data-url-name="${url.urlDataName}">
<!-- <span class="url-num-badge">[[${url.urlDataNum}]]</span> -->
[[${url.urlDataName}]]
</button>
</th:block>
@ -78,8 +124,8 @@
<th:block th:each="entry : ${groupedUrls}" th:if="${entry.key != '-'}">
<button type="button" class="custom-button subcat-folder-btn" th:data-target-subcat="${entry.key}"
th:id="'subcat-folder-' + ${#strings.replace(entry.key, ' ', '_')}">
<span class="url-num-badge"
th:text="${(entry.value != null && !entry.value.isEmpty() && entry.value.get(0).urlDataNum != null) ? entry.value.get(0).urlDataNum.substring(0, 1) : ''}">1</span>
<!-- <span
th:text="${(entry.value != null && !entry.value.isEmpty() && entry.value.get(0).urlDataNum != null) ? entry.value.get(0).urlDataNum.substring(0, 1) : ''}"></span> -->
<span class="subcat-title-text">[[${entry.key}]]</span>
</button>
</th:block>
@ -88,11 +134,11 @@
<th:block th:each="entry : ${groupedUrls}" th:if="${entry.key != '-'}">
<button type="button" th:each="url : ${entry.value}" th:attr="data-link = ${url.urlDataLink.startsWith('/urls')}
? @{${url.urlDataLink}}
: ${url.urlDataLink}" th:onclick="${url.urlDataLink.startsWith('/urls')}
: ${url.urlDataLink}, data-url-name = ${url.urlDataName}" th:onclick="${url.urlDataLink.startsWith('/urls')}
? 'window.location.href=this.dataset.link'
: 'window.open(this.dataset.link, \'_blank\')'" class="custom-button url-service-btn subcat-url-btn"
th:data-subcat="${entry.key}" style="display: none;">
<span class="url-num-badge">[[${url.urlDataNum}]]</span>
th:data-subcat="${entry.key}" style="display: none;" th:data-url-name="${url.urlDataName}">
<!-- <span class="url-num-badge">[[${url.urlDataNum}]]</span> -->
[[${url.urlDataName}]]
</button>
</th:block>
@ -115,6 +161,63 @@
<!-- Custom JS -->
<script th:inline="javascript">
const contextPath = /*[[@{/}]]*/ '';
// Function to show/hide credentials in the dropdown based on currently visible buttons
window.updateDropdownCredentials = function() {
const visibleUrlNames = new Set();
document.querySelectorAll(".url-service-btn").forEach(btn => {
if (btn.style.display !== "none") {
const name = btn.getAttribute("data-url-name");
if (name) visibleUrlNames.add(name.toLowerCase());
}
});
let visibleCount = 0;
document.querySelectorAll(".credential-item").forEach(item => {
const name = item.getAttribute("data-url-name");
if (name && visibleUrlNames.has(name.toLowerCase())) {
item.style.display = "block";
visibleCount++;
} else {
item.style.display = "none";
}
});
// Hide the credentials dropdown entirely if no credentials match the currently shown services
document.querySelectorAll(".credentials-dropdown").forEach(dd => {
if (visibleCount > 0) {
dd.style.setProperty("display", "block", "important");
} else {
dd.style.setProperty("display", "none", "important");
}
});
};
document.addEventListener("DOMContentLoaded", () => {
// Handle clicks inside the credentials dropdown menu
document.querySelectorAll('.dropdown-menu').forEach(menu => {
menu.addEventListener('click', function (e) {
// Prevent closing when clicking toggle-cat-pass or any other elements inside
e.stopPropagation();
if (e.target && e.target.classList.contains("toggle-cat-pass")) {
e.preventDefault();
const icon = e.target;
const targetId = icon.getAttribute("data-target");
const passwordElement = document.getElementById(targetId);
const originalPassword = icon.getAttribute("data-pass");
if (passwordElement.textContent.includes("*")) {
passwordElement.textContent = originalPassword;
icon.classList.replace("fa-eye", "fa-eye-slash");
} else {
passwordElement.textContent = "*".repeat(originalPassword.length);
icon.classList.replace("fa-eye-slash", "fa-eye");
}
}
});
});
});
</script>
<script th:src="@{/assets/js/home-script.js}" type="text/javascript" defer></script>
</body>

2
src/main/resources/templates/urls/update-url-data.html

@ -21,7 +21,7 @@
<body>
<!-- Navigation -->
<th:block th:replace="~{fragments/navbar :: navbar(curPage=${curPage}, isAdmin=${isAdmin})}"></th:block>
<th:block th:replace="~{fragments/navbar :: navbar(curPage=${curPage}, isAdmin=${isAdmin}, isLoggedIn=${isLoggedIn})}"></th:block>
<div class="container">
<div class="form-container">

Loading…
Cancel
Save