diff --git a/README.md b/README.md index 3b97d95..0fa9f52 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ In realms of connectedness, where devices roam free, A nexus of management, harm | spring.profiles.active | ✓ | Spring Boot environment | | jwt.public-key | ✓ | JWT public key file | | account-registry.url | ✓ | Account Register URL | +| device-registry.url | ✓ | Device Register URL | *Required: ✓ can be stored as text, and ✗ need to be stored as secret.* diff --git a/build.gradle.kts b/build.gradle.kts index f402985..88d3a73 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,7 +16,9 @@ dependencies { implementation(hlaeja.library.common.messages) implementation(hlaeja.library.jwt) implementation(hlaeja.projectreactor.kotlin.reactor.extensions) + implementation(hlaeja.springboot.redis.session) implementation(hlaeja.springboot.starter.actuator) + implementation(hlaeja.springboot.starter.redis) implementation(hlaeja.springboot.starter.security) implementation(hlaeja.springboot.starter.thymeleaf) implementation(hlaeja.springboot.starter.validation) diff --git a/gradle.properties b/gradle.properties index 6150f21..cad1528 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ kotlin.code.style=official version=0.2.0-SNAPSHOT -catalog=0.9.0 +catalog=0.10.0-SNAPSHOT container.port.host=9060 diff --git a/src/main/kotlin/ltd/hlaeja/Application.kt b/src/main/kotlin/ltd/hlaeja/Application.kt index dfbffee..adca0c4 100644 --- a/src/main/kotlin/ltd/hlaeja/Application.kt +++ b/src/main/kotlin/ltd/hlaeja/Application.kt @@ -1,12 +1,14 @@ package ltd.hlaeja import ltd.hlaeja.property.AccountRegistryProperty +import ltd.hlaeja.property.DeviceRegistryProperty import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.boot.runApplication @EnableConfigurationProperties( AccountRegistryProperty::class, + DeviceRegistryProperty::class, ) @SpringBootApplication class Application diff --git a/src/main/kotlin/ltd/hlaeja/configuration/SecurityConfiguration.kt b/src/main/kotlin/ltd/hlaeja/configuration/SecurityConfiguration.kt index bd35828..8ebf91d 100644 --- a/src/main/kotlin/ltd/hlaeja/configuration/SecurityConfiguration.kt +++ b/src/main/kotlin/ltd/hlaeja/configuration/SecurityConfiguration.kt @@ -36,6 +36,7 @@ class SecurityConfiguration { private fun AuthorizeExchangeSpec.adminPaths(): AuthorizeExchangeSpec.Access = pathMatchers( "/account/**", + "/type/**", ) private fun AuthorizeExchangeSpec.publicPaths(): AuthorizeExchangeSpec.Access = pathMatchers( diff --git a/src/main/kotlin/ltd/hlaeja/controller/AccountController.kt b/src/main/kotlin/ltd/hlaeja/controller/AccountController.kt index 7209a48..e4d617a 100644 --- a/src/main/kotlin/ltd/hlaeja/controller/AccountController.kt +++ b/src/main/kotlin/ltd/hlaeja/controller/AccountController.kt @@ -1,5 +1,7 @@ package ltd.hlaeja.controller +import jakarta.validation.constraints.Max +import jakarta.validation.constraints.Min import java.util.UUID import ltd.hlaeja.controller.validation.CreateGroup import ltd.hlaeja.controller.validation.EditGroup @@ -11,6 +13,7 @@ import ltd.hlaeja.form.AccountForm import ltd.hlaeja.service.AccountRegistryService import ltd.hlaeja.util.toAccountForm import ltd.hlaeja.util.toAccountRequest +import ltd.hlaeja.util.validationErrors import org.springframework.stereotype.Controller import org.springframework.ui.Model import org.springframework.validation.BindingResult @@ -30,6 +33,8 @@ class AccountController( companion object { const val DEFAULT_PAGE: Int = 1 const val DEFAULT_SIZE: Int = 25 + const val MIN: Long = 1 + const val MAX: Long = 100 } @GetMapping("/edit-{account}") @@ -50,22 +55,13 @@ class AccountController( @Validated(EditGroup::class) @ModelAttribute("accountForm") accountForm: AccountForm, bindingResult: BindingResult, model: Model, - ): Mono { - val validationErrors = if (bindingResult.hasErrors()) { - bindingResult.allErrors.map { error -> - error.defaultMessage ?: "Unknown validation error" - } - } else { - emptyList() - } - if (bindingResult.hasErrors()) { - model.addAttribute("accountForm", accountForm) - model.addAttribute("validationErrors", validationErrors) - model.addAttribute("roleGroups", accountRegistryService.getRoles()) - return Mono.just("account/edit") - } - - return Mono.just(accountForm) + ): Mono = if (bindingResult.hasErrors()) { + model.addAttribute("accountForm", accountForm) + model.addAttribute("validationErrors", validationErrors(bindingResult)) + model.addAttribute("roleGroups", accountRegistryService.getRoles()) + Mono.just("account/edit") + } else { + Mono.just(accountForm) .flatMap { accountRegistryService.updateAccount(account, it.toAccountRequest()) } .doOnNext { model.addAttribute("successMessage", listOf("Saved changes!!!")) @@ -82,6 +78,7 @@ class AccountController( "validationErrors", "Username already exists. Please choose another.", ) + else -> Pair("validationErrors", "An unexpected error occurred. Please try again later.") } @@ -107,21 +104,13 @@ class AccountController( @Validated(CreateGroup::class) @ModelAttribute("accountForm") accountForm: AccountForm, bindingResult: BindingResult, model: Model, - ): Mono { - val validationErrors = if (bindingResult.hasErrors()) { - bindingResult.allErrors.map { error -> - error.defaultMessage ?: "Unknown validation error" - } - } else { - emptyList() - } - if (bindingResult.hasErrors()) { - model.addAttribute("accountForm", accountForm) - model.addAttribute("validationErrors", validationErrors) - model.addAttribute("roleGroups", accountRegistryService.getRoles()) - return Mono.just("account/create") - } - return Mono.just(accountForm) + ): Mono = if (bindingResult.hasErrors()) { + model.addAttribute("accountForm", accountForm) + model.addAttribute("roleGroups", accountRegistryService.getRoles()) + model.addAttribute("validationErrors", validationErrors(bindingResult)) + Mono.just("account/create") + } else { + Mono.just(accountForm) .flatMap { accountRegistryService.addAccount(it.toAccountRequest()) } .map { "redirect:/account" } .onErrorResume { error -> @@ -135,33 +124,20 @@ class AccountController( } } - @GetMapping - fun getDefaultAccounts( + @GetMapping( + "", + "/page-{page}", + "/page-{page}/show-{show}", + ) + fun getAccounts( + @PathVariable(required = false) @Min(MIN) page: Int = DEFAULT_PAGE, + @PathVariable(required = false) @Min(MIN) @Max(MAX) show: Int = DEFAULT_SIZE, model: Model, - ): Mono = getAccounts(DEFAULT_PAGE, DEFAULT_SIZE, model) - - @GetMapping("/page-{page}") - fun getAccountsPage( - @PathVariable page: Int, - model: Model, - ): Mono = getAccounts(page, DEFAULT_SIZE, model) - - @GetMapping("/page-{page}/show-{size}") - fun getAccountsPageSize( - @PathVariable page: Int, - @PathVariable size: Int, - model: Model, - ): Mono = getAccounts(page, size, model) - - private fun getAccounts( - page: Int, - size: Int, - model: Model, - ) = accountRegistryService.getAccounts(page, size) + ): Mono = accountRegistryService.getAccounts(page, show) .collectList() .doOnNext { items -> model.addAttribute("items", items) - model.addAttribute("pagination", Pagination(page, size, items.size, DEFAULT_SIZE)) + model.addAttribute("pagination", Pagination(page, show, items.size, DEFAULT_SIZE)) } .then(Mono.just("account/users")) } diff --git a/src/main/kotlin/ltd/hlaeja/controller/TypeController.kt b/src/main/kotlin/ltd/hlaeja/controller/TypeController.kt new file mode 100644 index 0000000..a862ba3 --- /dev/null +++ b/src/main/kotlin/ltd/hlaeja/controller/TypeController.kt @@ -0,0 +1,142 @@ +package ltd.hlaeja.controller + +import jakarta.validation.constraints.Max +import jakarta.validation.constraints.Min +import java.util.UUID +import ltd.hlaeja.dto.Pagination +import ltd.hlaeja.exception.NoChangeException +import ltd.hlaeja.exception.NotFoundException +import ltd.hlaeja.exception.TypeNameDuplicateException +import ltd.hlaeja.form.TypeForm +import ltd.hlaeja.service.DeviceRegistryService +import ltd.hlaeja.util.toTypeForm +import ltd.hlaeja.util.toTypeRequest +import ltd.hlaeja.util.validationErrors +import org.springframework.stereotype.Controller +import org.springframework.ui.Model +import org.springframework.validation.BindingResult +import org.springframework.validation.annotation.Validated +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.ModelAttribute +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import reactor.core.publisher.Mono + +@Controller +class TypeController( + private val deviceRegistryService: DeviceRegistryService, +) { + companion object { + const val DEFAULT_PAGE: Int = 1 + const val DEFAULT_SIZE: Int = 25 + const val MIN: Long = 1 + const val MAX: Long = 100 + } + + @GetMapping( + "/type", + "/type/page-{page}", + "/type/page-{page}/show-{show}", + ) + fun getTypes( + @PathVariable(required = false) @Min(MIN) page: Int = DEFAULT_PAGE, + @PathVariable(required = false) @Min(MIN) @Max(MAX) show: Int = DEFAULT_SIZE, + model: Model, + ) = deviceRegistryService.getTypes(page, show) + .collectList() + .doOnNext { items -> + model.addAttribute("items", items) + model.addAttribute("pagination", Pagination(page, show, items.size, DEFAULT_SIZE)) + } + .then(Mono.just("device/type/list")) + + @GetMapping("/type/create") + fun getCreateType( + model: Model, + ): Mono = Mono.just("device/type/form") + .doOnNext { + model.addAttribute("typeForm", TypeForm()) + } + + @PostMapping("/type/create") + fun postCreateType( + @Validated @ModelAttribute("typeForm") typeForm: TypeForm, + bindingResult: BindingResult, + model: Model, + ): Mono = if (bindingResult.hasErrors()) { + model.addAttribute("typeForm", typeForm) + model.addAttribute("validationErrors", validationErrors(bindingResult)) + Mono.just("device/type/form") + } else { + Mono.just(typeForm) + .flatMap { deviceRegistryService.createType(it.toTypeRequest()) } + .map { "redirect:/type" } + .onErrorResume { error -> + val errorMessage = when (error) { + is TypeNameDuplicateException -> "Type name already exists. Please choose another." + else -> "An unexpected error occurred. Please try again later." + } + model.addAttribute("validationErrors", listOf(errorMessage)) + Mono.just("device/type/form") + } + } + + @GetMapping("/type-{type}") + fun getEditType( + @PathVariable type: UUID, + model: Model, + ): Mono = deviceRegistryService.getType(type) + .doOnNext { + model.addAttribute("type", it) + model.addAttribute("typeForm", it.toTypeForm()) + } + .then(Mono.just("device/type/form")) + + @PostMapping("/type-{type}") + fun postEditType( + @PathVariable type: UUID, + @Validated @ModelAttribute("typeForm") typeForm: TypeForm, + bindingResult: BindingResult, + model: Model, + ): Mono = if (bindingResult.hasErrors()) { + deviceRegistryService.getType(type) + .doOnNext { + model.addAttribute("type", it) + model.addAttribute("typeForm", typeForm) + model.addAttribute("validationErrors", validationErrors(bindingResult)) + } + .then( + Mono.just("device/type/form"), + ) + } else { + Mono.just(typeForm) + .flatMap { deviceRegistryService.updateType(type, it.toTypeRequest()) } + .doOnNext { + model.addAttribute("successMessage", listOf("Saved changes!!!")) + model.addAttribute("type", it) + model.addAttribute("typeForm", it.toTypeForm()) + } + .then(Mono.just("device/type/form")) + .onErrorResume { error -> + val errorMessage = when (error) { + is NoChangeException -> Pair("successMessage", "No change to save.") + is NotFoundException -> Pair("validationErrors", "User dont exists. how did this happen?") + is TypeNameDuplicateException -> Pair( + "validationErrors", + "Type name already exists. Please choose another.", + ) + + else -> Pair("validationErrors", "An unexpected error occurred. Please try again later.") + } + deviceRegistryService.getType(type) + .doOnNext { + model.addAttribute(errorMessage.first, listOf(errorMessage.second)) + model.addAttribute("type", it) + model.addAttribute("typeForm", typeForm) + } + .then( + Mono.just("device/type/form"), + ) + } + } +} diff --git a/src/main/kotlin/ltd/hlaeja/exception/DeviceRegistryException.kt b/src/main/kotlin/ltd/hlaeja/exception/DeviceRegistryException.kt new file mode 100644 index 0000000..b2f2aa0 --- /dev/null +++ b/src/main/kotlin/ltd/hlaeja/exception/DeviceRegistryException.kt @@ -0,0 +1,23 @@ +package ltd.hlaeja.exception + +@Suppress("unused") +open class DeviceRegistryException : HlaejaException { + + constructor() : super() + + constructor(message: String) : super(message) + + constructor(cause: Throwable) : super(cause) + + constructor( + message: String, + cause: Throwable, + ) : super(message, cause) + + constructor( + message: String, + cause: Throwable, + enableSuppression: Boolean, + writableStackTrace: Boolean, + ) : super(message, cause, enableSuppression, writableStackTrace) +} diff --git a/src/main/kotlin/ltd/hlaeja/exception/TypeNameDuplicateException.kt b/src/main/kotlin/ltd/hlaeja/exception/TypeNameDuplicateException.kt new file mode 100644 index 0000000..30c8d2c --- /dev/null +++ b/src/main/kotlin/ltd/hlaeja/exception/TypeNameDuplicateException.kt @@ -0,0 +1,23 @@ +package ltd.hlaeja.exception + +@Suppress("unused") +open class TypeNameDuplicateException : DeviceRegistryException { + + constructor() : super() + + constructor(message: String) : super(message) + + constructor(cause: Throwable) : super(cause) + + constructor( + message: String, + cause: Throwable, + ) : super(message, cause) + + constructor( + message: String, + cause: Throwable, + enableSuppression: Boolean, + writableStackTrace: Boolean, + ) : super(message, cause, enableSuppression, writableStackTrace) +} diff --git a/src/main/kotlin/ltd/hlaeja/form/TypeForm.kt b/src/main/kotlin/ltd/hlaeja/form/TypeForm.kt new file mode 100644 index 0000000..b2a0d99 --- /dev/null +++ b/src/main/kotlin/ltd/hlaeja/form/TypeForm.kt @@ -0,0 +1,10 @@ +package ltd.hlaeja.form + +import jakarta.validation.constraints.Size + +data class TypeForm( + @field:Size(min = 2, max = 50, message = "Name must be between 2 and 50 characters") + val name: String = "", + @field:Size(min = 2, max = 1000, message = "Description must be between 2 and 1000 characters") + val description: String = "", +) diff --git a/src/main/kotlin/ltd/hlaeja/property/DeviceRegistryProperty.kt b/src/main/kotlin/ltd/hlaeja/property/DeviceRegistryProperty.kt new file mode 100644 index 0000000..bee98ec --- /dev/null +++ b/src/main/kotlin/ltd/hlaeja/property/DeviceRegistryProperty.kt @@ -0,0 +1,8 @@ +package ltd.hlaeja.property + +import org.springframework.boot.context.properties.ConfigurationProperties + +@ConfigurationProperties(prefix = "device-registry") +data class DeviceRegistryProperty( + val url: String, +) diff --git a/src/main/kotlin/ltd/hlaeja/security/RemoteUserDetail.kt b/src/main/kotlin/ltd/hlaeja/security/RemoteUserDetail.kt index 6089ddf..bc6d35c 100644 --- a/src/main/kotlin/ltd/hlaeja/security/RemoteUserDetail.kt +++ b/src/main/kotlin/ltd/hlaeja/security/RemoteUserDetail.kt @@ -1,8 +1,14 @@ package ltd.hlaeja.security +import java.io.Serializable import java.util.UUID data class RemoteUserDetail( val id: UUID, val username: String, -) +) : Serializable { + companion object { + @Suppress("ConstPropertyName") + private const val serialVersionUID = 1L + } +} diff --git a/src/main/kotlin/ltd/hlaeja/service/DeviceRegistryService.kt b/src/main/kotlin/ltd/hlaeja/service/DeviceRegistryService.kt new file mode 100644 index 0000000..0a42dcf --- /dev/null +++ b/src/main/kotlin/ltd/hlaeja/service/DeviceRegistryService.kt @@ -0,0 +1,63 @@ +package ltd.hlaeja.service + +import java.util.UUID +import ltd.hlaeja.exception.DeviceRegistryException +import ltd.hlaeja.exception.HlaejaException +import ltd.hlaeja.library.deviceRegistry.Type +import ltd.hlaeja.library.deviceRegistry.Types +import ltd.hlaeja.property.DeviceRegistryProperty +import ltd.hlaeja.util.deviceRegistryType +import ltd.hlaeja.util.deviceRegistryTypes +import ltd.hlaeja.util.deviceRegistryTypesCreate +import ltd.hlaeja.util.deviceRegistryTypesUpdate +import org.springframework.http.HttpStatus.BAD_REQUEST +import org.springframework.stereotype.Service +import org.springframework.web.reactive.function.client.WebClient +import org.springframework.web.server.ResponseStatusException +import reactor.core.publisher.Flux +import reactor.core.publisher.Mono + +@Service +class DeviceRegistryService( + private val webClient: WebClient, + private val property: DeviceRegistryProperty, +) { + + fun getTypes( + page: Int, + show: Int, + ): Flux = webClient.deviceRegistryTypes(page, show, property) + + fun createType( + request: Type.Request, + ): Mono = webClient.deviceRegistryTypesCreate(request, property) + .onErrorResume { error -> + when (error) { + is DeviceRegistryException -> Mono.error(error) + else -> Mono.error(ResponseStatusException(BAD_REQUEST, error.message)) + } + } + + fun getType( + type: UUID, + ): Mono = webClient.deviceRegistryType(type, property) + .onErrorResume { error -> + when (error) { + is ResponseStatusException -> Mono.error(error) + else -> Mono.error(ResponseStatusException(BAD_REQUEST, error.message)) + } + } + + fun updateType( + type: UUID, + request: Type.Request, + ): Mono = webClient.deviceRegistryTypesUpdate(type, request, property) + .onErrorResume(::errorHandler) + + private fun errorHandler( + error: Throwable, + ): Mono = when (error) { + is HlaejaException -> Mono.error(error) + else -> Mono.error(ResponseStatusException(BAD_REQUEST, error.message)) + } +} diff --git a/src/main/kotlin/ltd/hlaeja/util/Controller.kt b/src/main/kotlin/ltd/hlaeja/util/Controller.kt new file mode 100644 index 0000000..a4c7dcd --- /dev/null +++ b/src/main/kotlin/ltd/hlaeja/util/Controller.kt @@ -0,0 +1,11 @@ +package ltd.hlaeja.util + +import org.springframework.validation.BindingResult + +fun validationErrors( + bindingResult: BindingResult, +): List = if (bindingResult.hasErrors()) { + bindingResult.allErrors.map { error -> error.defaultMessage ?: "Unknown validation error" } +} else { + emptyList() +} diff --git a/src/main/kotlin/ltd/hlaeja/util/DeviceRegisterWebClientCalls.kt b/src/main/kotlin/ltd/hlaeja/util/DeviceRegisterWebClientCalls.kt new file mode 100644 index 0000000..270b153 --- /dev/null +++ b/src/main/kotlin/ltd/hlaeja/util/DeviceRegisterWebClientCalls.kt @@ -0,0 +1,61 @@ +package ltd.hlaeja.util + +import java.util.UUID +import ltd.hlaeja.exception.DeviceRegistryException +import ltd.hlaeja.exception.NoChangeException +import ltd.hlaeja.exception.NotFoundException +import ltd.hlaeja.exception.TypeNameDuplicateException +import ltd.hlaeja.library.deviceRegistry.Type +import ltd.hlaeja.library.deviceRegistry.Types +import ltd.hlaeja.property.DeviceRegistryProperty +import org.springframework.http.HttpStatus.ACCEPTED +import org.springframework.http.HttpStatus.BAD_REQUEST +import org.springframework.http.HttpStatus.CONFLICT +import org.springframework.http.HttpStatus.NOT_FOUND +import org.springframework.web.reactive.function.client.WebClient +import org.springframework.web.server.ResponseStatusException +import reactor.core.publisher.Flux +import reactor.core.publisher.Mono + +fun WebClient.deviceRegistryTypes( + page: Int, + size: Int, + property: DeviceRegistryProperty, +): Flux = get() + .uri("${property.url}/types/page-$page/show-$size".also(::logCall)) + .retrieve() + .bodyToFlux(Types.Response::class.java) + +fun WebClient.deviceRegistryTypesCreate( + request: Type.Request, + property: DeviceRegistryProperty, +): Mono = post() + .uri("${property.url}/type".also(::logCall)) + .bodyValue(request) + .retrieve() + .onStatus(CONFLICT::equals) { throw TypeNameDuplicateException("Remote service returned 409") } + .onStatus(BAD_REQUEST::equals) { throw DeviceRegistryException("Remote service returned 400") } + .bodyToMono(Type.Response::class.java) + +fun WebClient.deviceRegistryType( + type: UUID, + property: DeviceRegistryProperty, +): Mono = get() + .uri("${property.url}/type-$type".also(::logCall)) + .retrieve() + .onStatus(NOT_FOUND::equals) { throw ResponseStatusException(NOT_FOUND) } + .bodyToMono(Type.Response::class.java) + +fun WebClient.deviceRegistryTypesUpdate( + type: UUID, + request: Type.Request, + property: DeviceRegistryProperty, +): Mono = put() + .uri("${property.url}/type-$type".also(::logCall)) + .bodyValue(request) + .retrieve() + .onStatus(ACCEPTED::equals) { throw NoChangeException("Remote service returned 202") } + .onStatus(BAD_REQUEST::equals) { throw DeviceRegistryException("Remote service returned 400") } + .onStatus(NOT_FOUND::equals) { throw NotFoundException("Remote service returned 404") } + .onStatus(CONFLICT::equals) { throw TypeNameDuplicateException("Remote service returned 409") } + .bodyToMono(Type.Response::class.java) diff --git a/src/main/kotlin/ltd/hlaeja/util/Mapping.kt b/src/main/kotlin/ltd/hlaeja/util/Mapping.kt index c68b40e..024045b 100644 --- a/src/main/kotlin/ltd/hlaeja/util/Mapping.kt +++ b/src/main/kotlin/ltd/hlaeja/util/Mapping.kt @@ -1,8 +1,10 @@ package ltd.hlaeja.util import ltd.hlaeja.form.AccountForm +import ltd.hlaeja.form.TypeForm import ltd.hlaeja.library.accountRegistry.Account import ltd.hlaeja.library.accountRegistry.Authentication +import ltd.hlaeja.library.deviceRegistry.Type import org.springframework.security.core.Authentication as SpringAuthentication fun SpringAuthentication.toAuthenticationRequest(): Authentication.Request = Authentication.Request( @@ -26,3 +28,13 @@ fun Account.Response.toAccountForm(): AccountForm = AccountForm( .replaceFirstChar { char -> char.uppercase() } }, ) + +fun TypeForm.toTypeRequest(): Type.Request = Type.Request( + name = name, + description = description, +) + +fun Type.Response.toTypeForm(): Type.Request = Type.Request( + name = name, + description = description, +) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 8916164..004ae23 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -9,6 +9,14 @@ spring: os: name: "%APP_BUILD_OS_NAME%" version: "%APP_BUILD_OS_VERSION%" + session: + timeout: 60m + + redis: + namespace: "spring:session:management" + data: + redis: + port: 6379 management: endpoints: @@ -42,10 +50,17 @@ spring: web: resources: static-locations: file:src/main/resources/static/ + data: + redis: + host: localhost + database: 2 account-registry: url: http://localhost:9050 +device-registry: + url: http://localhost:9010 + --- ########################## ### Docker environment ### @@ -54,10 +69,17 @@ spring: config: activate: on-profile: docker + data: + redis: + host: Redis + database: 2 account-registry: url: http://AccountRegistry:8080 +device-registry: + url: http://DeviceRegistry:8080 + --- ############################## ### Production environment ### diff --git a/src/main/resources/templates/account/users.html b/src/main/resources/templates/account/users.html index b867e9d..aa033aa 100644 --- a/src/main/resources/templates/account/users.html +++ b/src/main/resources/templates/account/users.html @@ -17,7 +17,7 @@
@@ -39,29 +39,13 @@
-
-
- Previous - Previous - Next - Next -
-
- Previous - Previous - Next - Next -
-
+ diff --git a/src/main/resources/templates/device/type/form.html b/src/main/resources/templates/device/type/form.html new file mode 100644 index 0000000..236a7bd --- /dev/null +++ b/src/main/resources/templates/device/type/form.html @@ -0,0 +1,44 @@ + + + + + +
+
+
+
+

+

+
+
+ Created: +
+
+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + + + + diff --git a/src/main/resources/templates/device/type/list.html b/src/main/resources/templates/device/type/list.html new file mode 100644 index 0000000..4143a1a --- /dev/null +++ b/src/main/resources/templates/device/type/list.html @@ -0,0 +1,55 @@ + + + + + +
+
+

Device Types

+
+
+
+ + + + + + + + + + + + + + + + + + + + +
NameTimeIDActions
No accounts found
Edit
+
+ +
+
+ + + + + diff --git a/src/main/resources/templates/layout.html b/src/main/resources/templates/layout.html index 2b7402d..8e04443 100644 --- a/src/main/resources/templates/layout.html +++ b/src/main/resources/templates/layout.html @@ -22,6 +22,7 @@