update paths

This commit is contained in:
2025-08-18 10:58:22 +02:00
parent 570981d5ac
commit 966c67e850
14 changed files with 45 additions and 44 deletions

View File

@@ -30,7 +30,7 @@ import org.springframework.web.bind.annotation.RequestMapping
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
@Controller @Controller
@RequestMapping("/account") @RequestMapping("/accounts")
class AccountController( class AccountController(
private val accountRegistryService: AccountRegistryService, private val accountRegistryService: AccountRegistryService,
) { ) {
@@ -110,7 +110,7 @@ class AccountController(
} else { } else {
Mono.just(accountForm) Mono.just(accountForm)
.flatMap { accountRegistryService.addAccount(it.toAccountRequest()) } .flatMap { accountRegistryService.addAccount(it.toAccountRequest()) }
.map { "redirect:/account" } .map { "redirect:/accounts" }
.onErrorResume { error -> .onErrorResume { error ->
val errorMessage = when (error) { val errorMessage = when (error) {
is UsernameDuplicateException -> "Username already exists. Please choose another." is UsernameDuplicateException -> "Username already exists. Please choose another."

View File

@@ -20,9 +20,9 @@ class DeviceController(
) { ) {
@GetMapping( @GetMapping(
"/device", "/devices",
"/device/page-{page}", "/devices/page-{page}",
"/device/page-{page}/show-{show}", "/devices/page-{page}/show-{show}",
) )
fun getDevice( fun getDevice(
@PathVariable(required = false) @Min(MIN) page: Int = DEFAULT_PAGE, @PathVariable(required = false) @Min(MIN) page: Int = DEFAULT_PAGE,

View File

@@ -19,9 +19,9 @@ class NodeController(
private val deviceRegistryService: DeviceRegistryService, private val deviceRegistryService: DeviceRegistryService,
) { ) {
@GetMapping( @GetMapping(
"/node", "/nodes",
"/node/page-{page}", "/nodes/page-{page}",
"/node/page-{page}/show-{show}", "/nodes/page-{page}/show-{show}",
) )
fun getNodes( fun getNodes(
@PathVariable(required = false) @Min(MIN) page: Int = DEFAULT_PAGE, @PathVariable(required = false) @Min(MIN) page: Int = DEFAULT_PAGE,

View File

@@ -24,17 +24,19 @@ import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.ModelAttribute import org.springframework.web.bind.annotation.ModelAttribute
import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestMapping
import reactor.core.publisher.Mono import reactor.core.publisher.Mono
@Controller @Controller
@RequestMapping("/types")
class TypeController( class TypeController(
private val deviceRegistryService: DeviceRegistryService, private val deviceRegistryService: DeviceRegistryService,
) { ) {
@GetMapping( @GetMapping(
"/type", "",
"/type/page-{page}", "/page-{page}",
"/type/page-{page}/show-{show}", "/page-{page}/show-{show}",
) )
fun getTypes( fun getTypes(
@PathVariable(required = false) @Min(MIN) page: Int = DEFAULT_PAGE, @PathVariable(required = false) @Min(MIN) page: Int = DEFAULT_PAGE,
@@ -48,7 +50,7 @@ class TypeController(
} }
.then(Mono.just("type/list")) .then(Mono.just("type/list"))
@GetMapping("/type/create") @GetMapping("/create")
fun getCreateType( fun getCreateType(
model: Model, model: Model,
): Mono<String> = Mono.just("type/form") ): Mono<String> = Mono.just("type/form")
@@ -56,7 +58,7 @@ class TypeController(
model.addAttribute("typeForm", TypeForm()) model.addAttribute("typeForm", TypeForm())
} }
@PostMapping("/type/create") @PostMapping("/create")
fun postCreateType( fun postCreateType(
@Validated @ModelAttribute("typeForm") typeForm: TypeForm, @Validated @ModelAttribute("typeForm") typeForm: TypeForm,
bindingResult: BindingResult, bindingResult: BindingResult,
@@ -68,7 +70,7 @@ class TypeController(
} else { } else {
Mono.just(typeForm) Mono.just(typeForm)
.flatMap { deviceRegistryService.createType(it.toTypeRequest()) } .flatMap { deviceRegistryService.createType(it.toTypeRequest()) }
.map { "redirect:/type" } .map { "redirect:/types" }
.onErrorResume { error -> .onErrorResume { error ->
val errorMessage = when (error) { val errorMessage = when (error) {
is TypeNameDuplicateException -> "Type name already exists. Please choose another." is TypeNameDuplicateException -> "Type name already exists. Please choose another."
@@ -79,7 +81,7 @@ class TypeController(
} }
} }
@GetMapping("/type-{type}") @GetMapping("/edit-{type}")
fun getEditType( fun getEditType(
@PathVariable type: UUID, @PathVariable type: UUID,
model: Model, model: Model,
@@ -90,7 +92,7 @@ class TypeController(
} }
.then(Mono.just("type/form")) .then(Mono.just("type/form"))
@PostMapping("/type-{type}") @PostMapping("/edit-{type}")
fun postEditType( fun postEditType(
@PathVariable type: UUID, @PathVariable type: UUID,
@Validated @ModelAttribute("typeForm") typeForm: TypeForm, @Validated @ModelAttribute("typeForm") typeForm: TypeForm,

View File

@@ -3,8 +3,8 @@ package ltd.hlaeja.security.authorize
import org.springframework.security.config.web.server.ServerHttpSecurity.AuthorizeExchangeSpec import org.springframework.security.config.web.server.ServerHttpSecurity.AuthorizeExchangeSpec
fun AuthorizeExchangeSpec.adminPaths(): AuthorizeExchangeSpec.Access = pathMatchers( fun AuthorizeExchangeSpec.adminPaths(): AuthorizeExchangeSpec.Access = pathMatchers(
"/account/**", "/accounts/**",
"/type/**", "/typse/**",
"/device/**", "/devices/**",
"/node/**", "/nodes/**",
) )

View File

@@ -11,7 +11,7 @@
<h2 class="text-lg sm:text-xl mb-4 terminal-glow">New Account Registration</h2> <h2 class="text-lg sm:text-xl mb-4 terminal-glow">New Account Registration</h2>
<hr class="border-green-900 mb-4"> <hr class="border-green-900 mb-4">
<th:block th:replace="~{messages :: messageDisplay(messageList=${validationErrors}, error=true, styleClass='text-red-600')}"/> <th:block th:replace="~{messages :: messageDisplay(messageList=${validationErrors}, error=true, styleClass='text-red-600')}"/>
<form th:action="@{/account/create}" th:method="post"> <form th:action="@{/accounts/create}" th:method="post">
<div class="bg-gray-800 p-6 rounded-lg border border-green-900"> <div class="bg-gray-800 p-6 rounded-lg border border-green-900">
<div class="mb-4"> <div class="mb-4">
<label for="username" class="block text-sm mb-2">Username</label> <label for="username" class="block text-sm mb-2">Username</label>
@@ -44,7 +44,7 @@
</div> </div>
</div> </div>
<div class="mt-4 flex justify-end space-x-4"> <div class="mt-4 flex justify-end space-x-4">
<a href="/account" class="bg-gray-800 hover:bg-gray-700 text-green-400 px-4 py-2 rounded border border-green-900 transition-colors inline-block">Cancel</a> <a href="/accounts" class="bg-gray-800 hover:bg-gray-700 text-green-400 px-4 py-2 rounded border border-green-900 transition-colors inline-block">Cancel</a>
<button type="submit" class="bg-green-900 hover:bg-green-800 text-green-400 px-4 py-2 rounded border border-green-600 transition-colors">Create</button> <button type="submit" class="bg-green-900 hover:bg-green-800 text-green-400 px-4 py-2 rounded border border-green-600 transition-colors">Create</button>
</div> </div>
</form> </form>

View File

@@ -8,7 +8,7 @@
<th:block th:replace="~{layout.html :: header}"/> <th:block th:replace="~{layout.html :: header}"/>
<main class="container mx-auto p-4 flex-grow flex items-center justify-center"> <main class="container mx-auto p-4 flex-grow flex items-center justify-center">
<div class="w-full max-w-4xl"> <div class="w-full max-w-4xl">
<form th:action="@{/account/edit-{account}(account = ${account})}" th:method="post"> <form th:action="@{/accounts/edit-{account}(account = ${account})}" th:method="post">
<div class="mb-4"> <div class="mb-4">
<h1 class="text-lg sm:text-xl mb-4 terminal-glow">Edit User <strong th:text="${accountForm.username}"/></h1> <h1 class="text-lg sm:text-xl mb-4 terminal-glow">Edit User <strong th:text="${accountForm.username}"/></h1>
<hr class="border-green-900 mb-4"> <hr class="border-green-900 mb-4">
@@ -59,7 +59,7 @@
</div> </div>
</div> </div>
<div class="mt-4 flex justify-end space-x-4"> <div class="mt-4 flex justify-end space-x-4">
<a href="/account" class="bg-gray-800 hover:bg-gray-700 text-green-400 px-4 py-2 rounded border border-green-900 transition-colors inline-block">Cancel</a> <a href="/accounts" class="bg-gray-800 hover:bg-gray-700 text-green-400 px-4 py-2 rounded border border-green-900 transition-colors inline-block">Cancel</a>
<button type="submit" class="bg-green-900 hover:bg-green-800 text-green-400 px-4 py-2 rounded border border-green-600 transition-colors">Update User</button> <button type="submit" class="bg-green-900 hover:bg-green-800 text-green-400 px-4 py-2 rounded border border-green-600 transition-colors">Update User</button>
</div> </div>
</div> </div>

View File

@@ -20,7 +20,7 @@
<span th:text="${pagination.size}"/> <span th:text="${pagination.size}"/>
</div> </div>
<div class="mt-[-2px]"> <div class="mt-[-2px]">
<a th:href="@{/account/create}" class="px-3 py-1 bg-gray-700 hover:bg-gray-600 rounded border border-green-900 transition-colors text-sm">Create New Account</a> <a th:href="@{/accounts/create}" class="px-3 py-1 bg-gray-700 hover:bg-gray-600 rounded border border-green-900 transition-colors text-sm">Create New Account</a>
</div> </div>
</div> </div>
<div class="overflow-x-auto"> <div class="overflow-x-auto">
@@ -38,11 +38,11 @@
<td class="py-2 px-4" th:text="${item.username}">username</td> <td class="py-2 px-4" th:text="${item.username}">username</td>
<td class="py-2 px-4 utcTimestamp" th:data-timestamp="${item.timestamp}">Loading...</td> <td class="py-2 px-4 utcTimestamp" th:data-timestamp="${item.timestamp}">Loading...</td>
<td class="py-2 px-4" th:text="${item.id}">ID</td> <td class="py-2 px-4" th:text="${item.id}">ID</td>
<td class="py-2 px-4"><a th:href="@{/account/edit-{id}(id = ${item.id})}">Edit</a></td> <td class="py-2 px-4"><a th:href="@{/accounts/edit-{id}(id = ${item.id})}">Edit</a></td>
</tr> </tr>
</table> </table>
</div> </div>
<th:block th:replace="~{pagination :: pagination('/account', ${pagination})}"/> <th:block th:replace="~{pagination :: pagination('/accounts', ${pagination})}"/>
</div> </div>
</main> </main>
<th:block th:replace="~{layout.html :: footer}"/> <th:block th:replace="~{layout.html :: footer}"/>

View File

@@ -12,8 +12,7 @@
<h2 class="text-lg sm:text-xl mb-4 terminal-glow">Confirm System Logout</h2> <h2 class="text-lg sm:text-xl mb-4 terminal-glow">Confirm System Logout</h2>
<p class="text-sm mb-6 text-green-600">Are you sure you want to terminate your session?</p> <p class="text-sm mb-6 text-green-600">Are you sure you want to terminate your session?</p>
<div class="flex justify-end space-x-4"> <div class="flex justify-end space-x-4">
<a href="/account/page-1/show-10" class="bg-gray-800 hover:bg-gray-700 text-green-400 px-4 py-2 rounded border border-green-900 transition-colors inline-block">Cancel</a> <button onclick="history.back()" class="bg-gray-800 hover:bg-gray-700 text-green-400 px-4 py-2 rounded border border-green-900 transition-colors">Go Back</button>
<!-- <a href="/account" class=" text-center bg-gray-700 hover:bg-gray-600 text-green-400 px-4 py-2 rounded border border-green-900 transition-colors">Cansel</a>-->
<form th:action="@{/logout}" th:method="post" class="flex-1"> <form th:action="@{/logout}" th:method="post" class="flex-1">
<button type="submit" class="w-full bg-red-900 hover:bg-red-800 text-green-400 px-4 py-2 rounded border border-red-600 transition-colors">Yes, Logout</button> <button type="submit" class="w-full bg-red-900 hover:bg-red-800 text-green-400 px-4 py-2 rounded border border-red-600 transition-colors">Yes, Logout</button>
</form> </form>

View File

@@ -8,7 +8,7 @@
<th:block th:replace="~{layout.html :: header}"/> <th:block th:replace="~{layout.html :: header}"/>
<main class="container mx-auto p-4 flex-grow"> <main class="container mx-auto p-4 flex-grow">
<div class="bg-gray-800 p-6 rounded-lg border border-green-900"> <div class="bg-gray-800 p-6 rounded-lg border border-green-900">
<h1 class="text-lg sm:text-xl mb-4 terminal-glow">Device</h1> <h1 class="text-lg sm:text-xl mb-4 terminal-glow">Devices</h1>
<hr class="border-green-900 mb-4"> <hr class="border-green-900 mb-4">
<div class="flex justify-between items-center mb-4"> <div class="flex justify-between items-center mb-4">
<div th:if="${pagination.start > pagination.size}" class="text-sm"> <div th:if="${pagination.start > pagination.size}" class="text-sm">
@@ -25,7 +25,7 @@
<thead> <thead>
<tr class="border-b border-green-900"> <tr class="border-b border-green-900">
<th class="py-2 px-4 text-left">ID</th> <th class="py-2 px-4 text-left">ID</th>
<th class="py-2 px-4 text-left">Time</th> <th class="py-2 px-4 text-left">Time <span></span></th>
<th class="py-2 px-4 text-left">Actions</th> <th class="py-2 px-4 text-left">Actions</th>
</tr> </tr>
</thead> </thead>
@@ -41,7 +41,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
<th:block th:replace="~{pagination :: pagination('/device', ${pagination})}"/> <th:block th:replace="~{pagination :: pagination('/devices', ${pagination})}"/>
</div> </div>
</main> </main>
<th:block th:replace="~{layout.html :: footer}"/> <th:block th:replace="~{layout.html :: footer}"/>

View File

@@ -32,11 +32,11 @@
</button> </button>
<div id="dropdown-menu" class="hidden absolute right-0 mt-2 w-48 bg-gray-800 border border-green-900 shadow-lg z-10"> <div id="dropdown-menu" class="hidden absolute right-0 mt-2 w-48 bg-gray-800 border border-green-900 shadow-lg z-10">
<th:block th:if="${remoteUser.hasRole('admin')}"> <th:block th:if="${remoteUser.hasRole('admin')}">
<a href="/account" class="block px-4 py-2 text-sm hover:bg-gray-700 hover:text-green-300 transition-colors">Account</a> <a href="/accounts" class="block px-4 py-2 text-sm hover:bg-gray-700 hover:text-green-300 transition-colors">Accounts</a>
<hr class="dropdown-divider"> <hr class="dropdown-divider">
<a href="/type" class="block px-4 py-2 text-sm hover:bg-gray-700 hover:text-green-300 transition-colors">Type</a> <a href="/types" class="block px-4 py-2 text-sm hover:bg-gray-700 hover:text-green-300 transition-colors">Types</a>
<a href="/device" class="block px-4 py-2 text-sm hover:bg-gray-700 hover:text-green-300 transition-colors">Device</a> <a href="/devices" class="block px-4 py-2 text-sm hover:bg-gray-700 hover:text-green-300 transition-colors">Devices</a>
<a href="/node" class="block px-4 py-2 text-sm hover:bg-gray-700 hover:text-green-300 transition-colors">Node</a> <a href="/nodes" class="block px-4 py-2 text-sm hover:bg-gray-700 hover:text-green-300 transition-colors">Nodes</a>
<hr class="dropdown-divider"> <hr class="dropdown-divider">
</th:block> </th:block>
<th:block th:if="${remoteUser.authenticated}"> <th:block th:if="${remoteUser.authenticated}">

View File

@@ -45,7 +45,7 @@
</tbody> </tbody>
</table> </table>
</div> </div>
<th:block th:replace="~{pagination :: pagination('/node', ${pagination})}"/> <th:block th:replace="~{pagination :: pagination('/nodes', ${pagination})}"/>
</div> </div>
</main> </main>
<th:block th:replace="~{layout.html :: footer}"/> <th:block th:replace="~{layout.html :: footer}"/>

View File

@@ -20,7 +20,7 @@
<hr class="border-green-900 mb-4"> <hr class="border-green-900 mb-4">
<th:block th:replace="~{messages :: messageDisplay(messageList=${validationErrors}, error=true, styleClass='text-red-600')}"/> <th:block th:replace="~{messages :: messageDisplay(messageList=${validationErrors}, error=true, styleClass='text-red-600')}"/>
<th:block th:replace="~{messages :: messageDisplay(messageList=${successMessage}, error=false, styleClass='text-green-600')}"/> <th:block th:replace="~{messages :: messageDisplay(messageList=${successMessage}, error=false, styleClass='text-green-600')}"/>
<form th:action="${type} == null ? @{/type/create} : @{/type-{id}(id=${type.id})}" th:method="post"> <form th:action="${type} == null ? @{/types/create} : @{/types/edit-{id}(id=${type.id})}" th:method="post">
<div class="bg-gray-800 p-6 rounded-lg border border-green-900"> <div class="bg-gray-800 p-6 rounded-lg border border-green-900">
<div class="mb-4"> <div class="mb-4">
<label for="username" class="block text-sm mb-2">Name</label> <label for="username" class="block text-sm mb-2">Name</label>
@@ -32,7 +32,7 @@
</div> </div>
</div> </div>
<div class="mt-4 flex justify-end space-x-4"> <div class="mt-4 flex justify-end space-x-4">
<a href="/type" class="bg-gray-800 hover:bg-gray-700 text-green-400 px-4 py-2 rounded border border-green-900 transition-colors inline-block" th:text="${type} == null ? 'Cancel' : 'Go Back'"/> <a href="/types" class="bg-gray-800 hover:bg-gray-700 text-green-400 px-4 py-2 rounded border border-green-900 transition-colors inline-block" th:text="${type} == null ? 'Cancel' : 'Go Back'"/>
<button type="submit" class="bg-green-900 hover:bg-green-800 text-green-400 px-4 py-2 rounded border border-green-600 transition-colors" th:text="${type} == null ? 'Create' : 'Save'"/> <button type="submit" class="bg-green-900 hover:bg-green-800 text-green-400 px-4 py-2 rounded border border-green-600 transition-colors" th:text="${type} == null ? 'Create' : 'Save'"/>
</div> </div>
</form> </form>

View File

@@ -8,7 +8,7 @@
<th:block th:replace="~{layout.html :: header}"/> <th:block th:replace="~{layout.html :: header}"/>
<main class="container mx-auto p-4 flex-grow"> <main class="container mx-auto p-4 flex-grow">
<div class="bg-gray-800 p-6 rounded-lg border border-green-900"> <div class="bg-gray-800 p-6 rounded-lg border border-green-900">
<h1 class="text-lg sm:text-xl mb-4 terminal-glow">Device Types</h1> <h1 class="text-lg sm:text-xl mb-4 terminal-glow">Types</h1>
<hr class="border-green-900 mb-4"> <hr class="border-green-900 mb-4">
<div class="flex justify-between items-center mb-4"> <div class="flex justify-between items-center mb-4">
<div th:if="${pagination.start > pagination.size}" class="text-sm"> <div th:if="${pagination.start > pagination.size}" class="text-sm">
@@ -20,14 +20,14 @@
<span th:text="${pagination.size}"/> <span th:text="${pagination.size}"/>
</div> </div>
<div class="mt-[-2px]"> <div class="mt-[-2px]">
<a th:href="@{/type/create}" class="px-3 py-1 bg-gray-700 hover:bg-gray-600 rounded border border-green-900 transition-colors text-sm">Create New Type</a> <a th:href="@{/types/create}" class="px-3 py-1 bg-gray-700 hover:bg-gray-600 rounded border border-green-900 transition-colors text-sm">Create New Type</a>
</div> </div>
</div> </div>
<div class="overflow-x-auto"> <div class="overflow-x-auto">
<table class="w-full text-sm"> <table class="w-full text-sm">
<thead> <thead>
<tr class="border-b border-green-900"> <tr class="border-b border-green-900">
<th class="py-2 px-4 text-left">Name</th> <th class="py-2 px-4 text-left">Name <span></span></th>
<th class="py-2 px-4 text-left">Time</th> <th class="py-2 px-4 text-left">Time</th>
<th class="py-2 px-4 text-left">ID</th> <th class="py-2 px-4 text-left">ID</th>
<th class="py-2 px-4 text-left">Actions</th> <th class="py-2 px-4 text-left">Actions</th>
@@ -41,12 +41,12 @@
<td th:text="${item.name}" class="py-2 px-4"></td> <td th:text="${item.name}" class="py-2 px-4"></td>
<td th:data-timestamp="${item.timestamp}" class="py-2 px-4 utcTimestamp"></td> <td th:data-timestamp="${item.timestamp}" class="py-2 px-4 utcTimestamp"></td>
<td th:text="${item.id}" class="py-2 px-4"></td> <td th:text="${item.id}" class="py-2 px-4"></td>
<td class="py-2 px-4"><a th:href="@{/type-{id}(id=${item.id})}">Edit</a></td> <td class="py-2 px-4"><a th:href="@{/types/edit-{id}(id=${item.id})}">Edit</a></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
<th:block th:replace="~{pagination :: pagination('/type', ${pagination})}"/> <th:block th:replace="~{pagination :: pagination('/types', ${pagination})}"/>
</div> </div>
</main> </main>
<th:block th:replace="~{layout.html :: footer}"/> <th:block th:replace="~{layout.html :: footer}"/>