From a9cdf3592dd679ef98c70d8153eab2dab6c67b42 Mon Sep 17 00:00:00 2001 From: Swordsteel Date: Thu, 31 Jul 2025 09:20:23 +0200 Subject: [PATCH] add default error - add error setting in application.yml - update tailwind.css - add error.html - add information.html - update UserAttribute with GuestUser - add ErrorAttributes - add GuestUser --- .../controller/advice/ErrorAttributes.kt | 29 ++ .../hlaeja/controller/advice/UserAttribute.kt | 23 +- .../ltd/hlaeja/security/user/GuestUser.kt | 16 + src/main/resources/application.yml | 17 + src/main/resources/static/css/tailwind.css | 319 ++++++++++++++++++ src/main/resources/templates/error/error.html | 58 ++++ .../templates/error/information.html | 21 ++ 7 files changed, 469 insertions(+), 14 deletions(-) create mode 100644 src/main/kotlin/ltd/hlaeja/controller/advice/ErrorAttributes.kt create mode 100644 src/main/kotlin/ltd/hlaeja/security/user/GuestUser.kt create mode 100644 src/main/resources/templates/error/error.html create mode 100644 src/main/resources/templates/error/information.html diff --git a/src/main/kotlin/ltd/hlaeja/controller/advice/ErrorAttributes.kt b/src/main/kotlin/ltd/hlaeja/controller/advice/ErrorAttributes.kt new file mode 100644 index 0000000..769f3aa --- /dev/null +++ b/src/main/kotlin/ltd/hlaeja/controller/advice/ErrorAttributes.kt @@ -0,0 +1,29 @@ +package ltd.hlaeja.controller.advice + +import kotlinx.coroutines.runBlocking +import ltd.hlaeja.security.RemoteAuthentication +import ltd.hlaeja.security.user.GuestUser +import org.springframework.boot.web.error.ErrorAttributeOptions +import org.springframework.boot.web.reactive.error.DefaultErrorAttributes +import org.springframework.security.core.context.SecurityContextImpl +import org.springframework.stereotype.Component +import org.springframework.web.reactive.function.server.ServerRequest +import org.springframework.web.reactive.function.server.awaitSession + +@Component +class ErrorAttributes : DefaultErrorAttributes(), GuestUser { + + override fun getErrorAttributes( + serverRequest: ServerRequest, + errorAttributeOptions: ErrorAttributeOptions, + ): MutableMap = + super.getErrorAttributes(serverRequest, errorAttributeOptions) + .also { attribute -> + attribute["remoteUser"] = runBlocking { + serverRequest.awaitSession() + .attributes["SPRING_SECURITY_CONTEXT"] + ?.let { context -> (context as SecurityContextImpl).authentication } + ?: guestUser() + } as RemoteAuthentication + } +} diff --git a/src/main/kotlin/ltd/hlaeja/controller/advice/UserAttribute.kt b/src/main/kotlin/ltd/hlaeja/controller/advice/UserAttribute.kt index d595d7b..7ef6401 100644 --- a/src/main/kotlin/ltd/hlaeja/controller/advice/UserAttribute.kt +++ b/src/main/kotlin/ltd/hlaeja/controller/advice/UserAttribute.kt @@ -1,29 +1,24 @@ package ltd.hlaeja.controller.advice -import java.util.UUID import kotlinx.coroutines.reactive.awaitFirstOrNull import ltd.hlaeja.security.RemoteAuthentication -import ltd.hlaeja.security.RemoteUserDetail +import ltd.hlaeja.security.user.GuestUser import org.springframework.security.core.context.ReactiveSecurityContextHolder import org.springframework.ui.Model import org.springframework.web.bind.annotation.ControllerAdvice import org.springframework.web.bind.annotation.ModelAttribute @ControllerAdvice -class UserAttribute { +class UserAttribute : GuestUser { @ModelAttribute suspend fun remoteUser(model: Model) { - val remoteAuthentication: RemoteAuthentication = ReactiveSecurityContextHolder.getContext() - .awaitFirstOrNull() - ?.let { it.authentication as RemoteAuthentication } - ?: RemoteAuthentication( - RemoteUserDetail( - UUID.fromString("00000000-0000-0000-0000-000000000000"), - "n/a", - ), - mutableListOf(), - ) - model.addAttribute("remoteUser", remoteAuthentication) + model.addAttribute( + "remoteUser", + ReactiveSecurityContextHolder.getContext() + .awaitFirstOrNull() + ?.let { it.authentication as RemoteAuthentication } + ?: guestUser(), + ) } } diff --git a/src/main/kotlin/ltd/hlaeja/security/user/GuestUser.kt b/src/main/kotlin/ltd/hlaeja/security/user/GuestUser.kt new file mode 100644 index 0000000..c84e103 --- /dev/null +++ b/src/main/kotlin/ltd/hlaeja/security/user/GuestUser.kt @@ -0,0 +1,16 @@ +package ltd.hlaeja.security.user + +import java.util.UUID +import ltd.hlaeja.security.RemoteAuthentication +import ltd.hlaeja.security.RemoteUserDetail + +interface GuestUser { + + fun guestUser(): RemoteAuthentication = RemoteAuthentication( + RemoteUserDetail( + UUID.fromString("00000000-0000-0000-0000-000000000000"), + "n/a", + ), + mutableListOf(), + ) +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 3f8f3f7..ae62301 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -17,6 +17,12 @@ spring: redis: port: 6379 +server: + error: + include-exception: false + include-message: never + include-stacktrace: never + management: endpoints: access: @@ -55,6 +61,12 @@ spring: host: localhost database: 2 +server: + error: + include-exception: true + include-message: always + include-stacktrace: always + account-registry: url: http://localhost:9050 @@ -74,6 +86,11 @@ spring: host: Redis database: 2 +server: + error: + include-exception: true + include-message: always + account-registry: url: http://AccountRegistry:8080 diff --git a/src/main/resources/static/css/tailwind.css b/src/main/resources/static/css/tailwind.css index a6d701f..e7a1351 100644 --- a/src/main/resources/static/css/tailwind.css +++ b/src/main/resources/static/css/tailwind.css @@ -15,16 +15,21 @@ --color-green-600: oklch(62.7% 0.194 149.214); --color-green-800: oklch(44.8% 0.119 151.328); --color-green-900: oklch(39.3% 0.095 152.535); + --color-teal-100: oklch(95.3% 0.051 180.801); + --color-teal-600: oklch(60% 0.118 184.704); --color-gray-500: oklch(55.1% 0.027 264.364); --color-gray-600: oklch(44.6% 0.03 256.802); --color-gray-700: oklch(37.3% 0.034 259.733); --color-gray-800: oklch(27.8% 0.033 256.848); --color-gray-900: oklch(21% 0.034 264.665); + --color-zinc-300: oklch(87.1% 0.006 286.286); + --color-zinc-400: oklch(70.5% 0.015 286.067); --color-stone-400: oklch(70.9% 0.01 56.259); --color-black: #000; --color-white: #fff; --spacing: 0.25rem; --container-md: 28rem; + --container-2xl: 42rem; --container-3xl: 48rem; --container-4xl: 56rem; --text-xs: 0.75rem; @@ -39,8 +44,20 @@ --text-xl--line-height: calc(1.75 / 1.25); --text-2xl: 1.5rem; --text-2xl--line-height: calc(2 / 1.5); + --text-3xl: 1.875rem; + --text-3xl--line-height: calc(2.25 / 1.875); + --text-4xl: 2.25rem; + --text-4xl--line-height: calc(2.5 / 2.25); + --text-5xl: 3rem; + --text-5xl--line-height: 1; + --text-6xl: 3.75rem; + --text-6xl--line-height: 1; + --text-7xl: 4.5rem; + --text-7xl--line-height: 1; --font-weight-semibold: 600; + --font-weight-bold: 700; --leading-relaxed: 1.625; + --radius-md: 0.375rem; --radius-lg: 0.5rem; --default-transition-duration: 150ms; --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); @@ -245,6 +262,9 @@ .mt-auto { margin-top: auto; } + .mb-0 { + margin-bottom: calc(var(--spacing) * 0); + } .mb-2 { margin-bottom: calc(var(--spacing) * 2); } @@ -254,6 +274,12 @@ .mb-6 { margin-bottom: calc(var(--spacing) * 6); } + .mb-8 { + margin-bottom: calc(var(--spacing) * 8); + } + .mb-50 { + margin-bottom: calc(var(--spacing) * 50); + } .block { display: block; } @@ -269,21 +295,69 @@ .inline-block { display: inline-block; } + .table { + display: table; + } + .h-2 { + height: calc(var(--spacing) * 2); + } .h-6 { height: calc(var(--spacing) * 6); } + .h-12 { + height: calc(var(--spacing) * 12); + } + .h-20 { + height: calc(var(--spacing) * 20); + } + .h-25 { + height: calc(var(--spacing) * 25); + } + .h-30 { + height: calc(var(--spacing) * 30); + } + .h-full { + height: 100%; + } + .min-h-\[calc\(100vh-4rem\)\] { + min-height: calc(100vh - 4rem); + } + .min-h-\[calc\(100vh-6rem\)\] { + min-height: calc(100vh - 6rem); + } + .min-h-\[calc\(100vh-10rem\)\] { + min-height: calc(100vh - 10rem); + } .min-h-screen { min-height: 100vh; } .w-6 { width: calc(var(--spacing) * 6); } + .w-12 { + width: calc(var(--spacing) * 12); + } .w-48 { width: calc(var(--spacing) * 48); } + .w-100 { + width: calc(var(--spacing) * 100); + } + .w-125 { + width: calc(var(--spacing) * 125); + } + .w-150 { + width: calc(var(--spacing) * 150); + } + .w-400 { + width: calc(var(--spacing) * 400); + } .w-full { width: 100%; } + .max-w-2xl { + max-width: var(--container-2xl); + } .max-w-3xl { max-width: var(--container-3xl); } @@ -299,6 +373,12 @@ .flex-grow { flex-grow: 1; } + .border-collapse { + border-collapse: collapse; + } + .resize { + resize: both; + } .list-none { list-style-type: none; } @@ -353,12 +433,18 @@ .overflow-y-auto { overflow-y: auto; } + .scroll-smooth { + scroll-behavior: smooth; + } .rounded { border-radius: 0.25rem; } .rounded-lg { border-radius: var(--radius-lg); } + .rounded-md { + border-radius: var(--radius-md); + } .border { border-style: var(--tw-border-style); border-width: 1px; @@ -401,6 +487,29 @@ .bg-stone-400 { background-color: var(--color-stone-400); } + .bg-teal-600 { + background-color: var(--color-teal-600); + } + .bg-gradient-to-br { + --tw-gradient-position: to bottom right in oklab; + background-image: linear-gradient(var(--tw-gradient-stops)); + } + .from-zinc-300 { + --tw-gradient-from: var(--color-zinc-300); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .via-zinc-400 { + --tw-gradient-via: var(--color-zinc-400); + --tw-gradient-via-stops: var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-via-stops); + } + .to-stone-400 { + --tw-gradient-to: var(--color-stone-400); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } + .fill-green-400 { + fill: var(--color-green-400); + } .p-4 { padding: calc(var(--spacing) * 4); } @@ -422,15 +531,50 @@ .py-2 { padding-block: calc(var(--spacing) * 2); } + .py-3 { + padding-block: calc(var(--spacing) * 3); + } .py-4 { padding-block: calc(var(--spacing) * 4); } + .py-5 { + padding-block: calc(var(--spacing) * 5); + } + .py-10 { + padding-block: calc(var(--spacing) * 10); + } + .py-12 { + padding-block: calc(var(--spacing) * 12); + } .text-center { text-align: center; } .text-left { text-align: left; } + .font-mono { + font-family: var(--font-mono); + } + .text-2xl { + font-size: var(--text-2xl); + line-height: var(--tw-leading, var(--text-2xl--line-height)); + } + .text-3xl { + font-size: var(--text-3xl); + line-height: var(--tw-leading, var(--text-3xl--line-height)); + } + .text-4xl { + font-size: var(--text-4xl); + line-height: var(--tw-leading, var(--text-4xl--line-height)); + } + .text-5xl { + font-size: var(--text-5xl); + line-height: var(--tw-leading, var(--text-5xl--line-height)); + } + .text-7xl { + font-size: var(--text-7xl); + line-height: var(--tw-leading, var(--text-7xl--line-height)); + } .text-base { font-size: var(--text-base); line-height: var(--tw-leading, var(--text-base--line-height)); @@ -455,10 +599,20 @@ --tw-leading: var(--leading-relaxed); line-height: var(--leading-relaxed); } + .font-bold { + --tw-font-weight: var(--font-weight-bold); + font-weight: var(--font-weight-bold); + } .font-semibold { --tw-font-weight: var(--font-weight-semibold); font-weight: var(--font-weight-semibold); } + .break-words { + overflow-wrap: break-word; + } + .whitespace-pre-wrap { + white-space: pre-wrap; + } .text-black { color: var(--color-black); } @@ -474,13 +628,23 @@ .text-red-600 { color: var(--color-red-600); } + .text-teal-100 { + color: var(--color-teal-100); + } .text-white { color: var(--color-white); } + .underline { + text-decoration-line: underline; + } .shadow-lg { --tw-shadow: 0 10px 15px -3px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 4px 6px -4px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); } + .outline { + outline-style: var(--tw-outline-style); + outline-width: 1px; + } .filter { filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); } @@ -551,6 +715,24 @@ line-height: var(--tw-leading, var(--text-2xl--line-height)); } } + .sm\:text-3xl { + @media (width >= 40rem) { + font-size: var(--text-3xl); + line-height: var(--tw-leading, var(--text-3xl--line-height)); + } + } + .sm\:text-4xl { + @media (width >= 40rem) { + font-size: var(--text-4xl); + line-height: var(--tw-leading, var(--text-4xl--line-height)); + } + } + .sm\:text-5xl { + @media (width >= 40rem) { + font-size: var(--text-5xl); + line-height: var(--tw-leading, var(--text-5xl--line-height)); + } + } .sm\:text-base { @media (width >= 40rem) { font-size: var(--text-base); @@ -569,11 +751,91 @@ line-height: var(--tw-leading, var(--text-xl--line-height)); } } + .md\:h-20 { + @media (width >= 48rem) { + height: calc(var(--spacing) * 20); + } + } + .md\:h-24 { + @media (width >= 48rem) { + height: calc(var(--spacing) * 24); + } + } + .md\:h-40 { + @media (width >= 48rem) { + height: calc(var(--spacing) * 40); + } + } + .md\:h-50 { + @media (width >= 48rem) { + height: calc(var(--spacing) * 50); + } + } + .md\:h-100 { + @media (width >= 48rem) { + height: calc(var(--spacing) * 100); + } + } + .md\:h-200 { + @media (width >= 48rem) { + height: calc(var(--spacing) * 200); + } + } + .md\:w-20 { + @media (width >= 48rem) { + width: calc(var(--spacing) * 20); + } + } + .md\:w-24 { + @media (width >= 48rem) { + width: calc(var(--spacing) * 24); + } + } + .md\:w-200 { + @media (width >= 48rem) { + width: calc(var(--spacing) * 200); + } + } + .md\:w-320 { + @media (width >= 48rem) { + width: calc(var(--spacing) * 320); + } + } .md\:grid-cols-2 { @media (width >= 48rem) { grid-template-columns: repeat(2, minmax(0, 1fr)); } } + .md\:text-2xl { + @media (width >= 48rem) { + font-size: var(--text-2xl); + line-height: var(--tw-leading, var(--text-2xl--line-height)); + } + } + .md\:text-4xl { + @media (width >= 48rem) { + font-size: var(--text-4xl); + line-height: var(--tw-leading, var(--text-4xl--line-height)); + } + } + .md\:text-5xl { + @media (width >= 48rem) { + font-size: var(--text-5xl); + line-height: var(--tw-leading, var(--text-5xl--line-height)); + } + } + .md\:text-6xl { + @media (width >= 48rem) { + font-size: var(--text-6xl); + line-height: var(--tw-leading, var(--text-6xl--line-height)); + } + } + .md\:text-7xl { + @media (width >= 48rem) { + font-size: var(--text-7xl); + line-height: var(--tw-leading, var(--text-7xl--line-height)); + } + } } @property --tw-space-y-reverse { syntax: "*"; @@ -590,6 +852,48 @@ inherits: false; initial-value: solid; } +@property --tw-gradient-position { + syntax: "*"; + inherits: false; +} +@property --tw-gradient-from { + syntax: ""; + inherits: false; + initial-value: #0000; +} +@property --tw-gradient-via { + syntax: ""; + inherits: false; + initial-value: #0000; +} +@property --tw-gradient-to { + syntax: ""; + inherits: false; + initial-value: #0000; +} +@property --tw-gradient-stops { + syntax: "*"; + inherits: false; +} +@property --tw-gradient-via-stops { + syntax: "*"; + inherits: false; +} +@property --tw-gradient-from-position { + syntax: ""; + inherits: false; + initial-value: 0%; +} +@property --tw-gradient-via-position { + syntax: ""; + inherits: false; + initial-value: 50%; +} +@property --tw-gradient-to-position { + syntax: ""; + inherits: false; + initial-value: 100%; +} @property --tw-leading { syntax: "*"; inherits: false; @@ -663,6 +967,11 @@ inherits: false; initial-value: 0 0 #0000; } +@property --tw-outline-style { + syntax: "*"; + inherits: false; + initial-value: solid; +} @property --tw-blur { syntax: "*"; inherits: false; @@ -722,6 +1031,15 @@ --tw-space-y-reverse: 0; --tw-space-x-reverse: 0; --tw-border-style: solid; + --tw-gradient-position: initial; + --tw-gradient-from: #0000; + --tw-gradient-via: #0000; + --tw-gradient-to: #0000; + --tw-gradient-stops: initial; + --tw-gradient-via-stops: initial; + --tw-gradient-from-position: 0%; + --tw-gradient-via-position: 50%; + --tw-gradient-to-position: 100%; --tw-leading: initial; --tw-font-weight: initial; --tw-shadow: 0 0 #0000; @@ -738,6 +1056,7 @@ --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; + --tw-outline-style: solid; --tw-blur: initial; --tw-brightness: initial; --tw-contrast: initial; diff --git a/src/main/resources/templates/error/error.html b/src/main/resources/templates/error/error.html new file mode 100644 index 0000000..8a8e1dd --- /dev/null +++ b/src/main/resources/templates/error/error.html @@ -0,0 +1,58 @@ + + + + Error - Hlæja + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

This page flopped!

+ + +

Something went wrong in the meme universe! Try again or head back home for more lulz!

+ Return Home +
+
+ + + + + + + + + + + diff --git a/src/main/resources/templates/error/information.html b/src/main/resources/templates/error/information.html new file mode 100644 index 0000000..e338f98 --- /dev/null +++ b/src/main/resources/templates/error/information.html @@ -0,0 +1,21 @@ + + + + + +

Message

+
+ +

Exception

+
+
+ +
+
+

Stack Trace

+
Stack Trace
+
+
+
+ +