From f83c9446656dd089c751674d30ae44ffae9d4777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Horv=C3=A1th=20Istv=C3=A1n?= Date: Thu, 29 Aug 2024 10:10:25 +0200 Subject: [PATCH] Make forced countdown optional based on role --- .../bme/sch/cmsch/component/SettingProxy.kt | 7 ++-- .../component/app/ApplicationApiController.kt | 6 ++-- .../component/countdown/CountdownApiFilter.kt | 30 ++++++++--------- .../component/countdown/CountdownComponent.kt | 32 +++++++++++-------- .../templates/componentSettings.html | 31 ++++-------------- frontend/src/api/contexts/config/types.ts | 4 +-- .../src/pages/countdown/countdown.page.tsx | 2 +- 7 files changed, 49 insertions(+), 63 deletions(-) diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/SettingProxy.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/SettingProxy.kt index ea710f44d..4be041c8a 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/SettingProxy.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/SettingProxy.kt @@ -108,7 +108,8 @@ class MinRoleSettingProxy( defaultValue: String, fieldName: String = "", description: String = "", - minRoleToEdit: RoleType = RoleType.STAFF + minRoleToEdit: RoleType = RoleType.STAFF, + val grantedForRoles: List = listOf(RoleType.ADMIN.name, RoleType.SUPERUSER.name) ) : SettingProxy( componentPropertyService, component, property, defaultValue = defaultValue, type = SettingType.MIN_ROLE, @@ -120,11 +121,11 @@ class MinRoleSettingProxy( val ALL_ROLES by lazy { RoleType.entries.joinToString(",") { it.name } } val ALL_ROLES_FROM_ATTENDEE by lazy { RoleType.entries.filter { it.value >= RoleType.ATTENDEE.value }.joinToString(",") { it.name } } val ALL_ROLES_FROM_PRIVILEGED by lazy { RoleType.entries.filter { it.value >= RoleType.PRIVILEGED.value }.joinToString(",") { it.name } } + val ALL_POSSIBLE_ROLES by lazy { RoleType.entries.filter { it.value != RoleType.NOBODY.value } } } fun isAvailableForRole(role: RoleType): Boolean { - return rawValue.split(",").contains(role.name) || role == RoleType.ADMIN || role == RoleType.SUPERUSER + return rawValue.split(",").contains(role.name) || grantedForRoles.contains(role.name) } } - diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/app/ApplicationApiController.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/app/ApplicationApiController.kt index 163934553..d3e4dde0e 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/app/ApplicationApiController.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/app/ApplicationApiController.kt @@ -35,10 +35,12 @@ class ApplicationApiController( val role = auth?.getUserOrNull()?.role ?: RoleType.GUEST if (countdownComponent.isPresent) { val countdown = countdownComponent.orElseThrow() - if (countdown.isBlockedAt(clock.getTimeInSeconds())) { + if (countdown.isBlockedAt(clock.getTimeInSeconds(), role)) { val components = mapOf( applicationComponent.component to appComponentFields(), - countdown.component to countdown.attachConstants(), + countdown.component to countdown.attachConstants().toMutableMap().also { + it["showOnly"] = true + }, stylingComponent.component to stylingComponent.attachConstants() ) return ApplicationConfigDto( diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/countdown/CountdownApiFilter.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/countdown/CountdownApiFilter.kt index 400668159..8bcf3c914 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/countdown/CountdownApiFilter.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/countdown/CountdownApiFilter.kt @@ -1,31 +1,27 @@ package hu.bme.sch.cmsch.component.countdown +import hu.bme.sch.cmsch.model.RoleType import hu.bme.sch.cmsch.service.TimeService -import org.springframework.web.filter.GenericFilterBean -import java.io.IOException +import hu.bme.sch.cmsch.util.getUserOrNull import jakarta.servlet.FilterChain -import jakarta.servlet.ServletException -import jakarta.servlet.ServletRequest -import jakarta.servlet.ServletResponse import jakarta.servlet.http.HttpServletRequest import jakarta.servlet.http.HttpServletResponse +import org.springframework.security.core.context.SecurityContextHolder +import org.springframework.web.filter.OncePerRequestFilter class CountdownApiFilter( private val countdown: CountdownComponent, private val clock: TimeService -) : GenericFilterBean() { +) : OncePerRequestFilter() { - @Throws(IOException::class, ServletException::class) - override fun doFilter(req: ServletRequest, res: ServletResponse, filterChain: FilterChain) { - val httpRequest = req as HttpServletRequest - val httpResponse = res as HttpServletResponse - - if (httpRequest.servletPath.startsWith("/api/") - && !httpRequest.servletPath.startsWith("/api/app") - && countdown.isBlockedAt(clock.getTimeInSeconds()) - ) { - httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST, "Countdown is not finished") - return + override fun doFilterInternal(req: HttpServletRequest, res: HttpServletResponse, filterChain: FilterChain) { + if (req.servletPath.startsWith("/api/") && !req.servletPath.startsWith("/api/app")) { + val cmschUser = SecurityContextHolder.getContext()?.authentication?.getUserOrNull() + val role = cmschUser?.role ?: RoleType.GUEST + if (countdown.isBlockedAt(clock.getTimeInSeconds(), role)) { + res.sendError(HttpServletResponse.SC_BAD_REQUEST, "Countdown is not finished") + return + } } filterChain.doFilter(req, res) } diff --git a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/countdown/CountdownComponent.kt b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/countdown/CountdownComponent.kt index daa9f42ca..05cde2234 100644 --- a/backend/src/main/kotlin/hu/bme/sch/cmsch/component/countdown/CountdownComponent.kt +++ b/backend/src/main/kotlin/hu/bme/sch/cmsch/component/countdown/CountdownComponent.kt @@ -33,17 +33,20 @@ class CountdownComponent( title, minRole, enabled, - showOnly, + showOnlyCountdownForRoles, + keepOnAfterCountdownOver, topMessage, timeToCountTo, - informativeOnly, imageUrl, blurredImage, ) } - fun isBlockedAt(timeInSec: Long): Boolean { - return enabled.isValueTrue() && showOnly.isValueTrue() && (informativeOnly.isValueTrue() || ((timeToCountTo.getValue().toLongOrNull() ?: 0) > timeInSec)) + fun isBlockedAt(timeInSec: Long, role: RoleType): Boolean { + if (!enabled.isValueTrue()) return false + if (!showOnlyCountdownForRoles.isAvailableForRole(role)) return false + val isCountdownOver = (timeToCountTo.getValue().toLongOrNull() ?: 0) < timeInSec + return (keepOnAfterCountdownOver.isValueTrue() || !isCountdownOver) } val countdownGroup = SettingProxy(componentSettingService, component, @@ -70,10 +73,17 @@ class CountdownComponent( fieldName = "Bekapcsolva", description = "Legyen aktív a visszaszámlálás komponens" ) - val showOnly = SettingProxy(componentSettingService, component, - "showOnly", "true", type = SettingType.BOOLEAN, - fieldName = "Erőltetett", description = "Más komponensek ne legyenek elérhetőek. " + - "Csak akkor működik, ha be van kapcsolva a komponens." + val showOnlyCountdownForRoles = MinRoleSettingProxy(componentSettingService, component, + "showOnlyCountdownForRoles", MinRoleSettingProxy.ALL_ROLES, + fieldName = "Kinek legyen erőltetett", description = "Ezek a roleok számára más komponensek ne legyenek elérhetőek. " + + "Csak akkor működik, ha be van kapcsolva a komponens.", + minRoleToEdit = RoleType.SUPERUSER, grantedForRoles = ArrayList() // Thymeleaf doesn't like emptyList() (EmptyList) + ) + + val keepOnAfterCountdownOver = SettingProxy(componentSettingService, component, + "keepOnAfterCountdownOver", "false", type = SettingType.BOOLEAN, + fieldName = "Ne engedjen be az oldalra lejárat után", + description = "Ha be van kapcsolva és erőltetett a visszaszámláló a felhasználó, akkor a lejárta után sem enged az oldalhoz hozzáférni" ) val topMessage = SettingProxy(componentSettingService, component, @@ -87,12 +97,6 @@ class CountdownComponent( fieldName = "Visszaszámlálás eddig" ) - val informativeOnly = SettingProxy(componentSettingService, component, - "informativeOnly", "false", type = SettingType.BOOLEAN, - fieldName = "Tájékoztató jellegű", - description = "Ha be van kapcsolva akkor a lejárta után sem enged az oldalhoz hozzáférni" - ) - val imageUrl = SettingProxy(componentSettingService, component, "imageUrl", "https://warp.sch.bme.hu/kir-dev/cmsch/countdown-bg.png", type = SettingType.URL, fieldName = "Háttérkép URL-je", description = "" diff --git a/backend/src/main/resources/templates/componentSettings.html b/backend/src/main/resources/templates/componentSettings.html index 88dfaff79..0ca2ecec2 100644 --- a/backend/src/main/resources/templates/componentSettings.html +++ b/backend/src/main/resources/templates/componentSettings.html @@ -455,36 +455,19 @@

Group Name

- + - + - - - - - - - - diff --git a/frontend/src/api/contexts/config/types.ts b/frontend/src/api/contexts/config/types.ts index de2be5fdf..9696ff411 100644 --- a/frontend/src/api/contexts/config/types.ts +++ b/frontend/src/api/contexts/config/types.ts @@ -77,10 +77,10 @@ export interface Footer { export interface Countdown { title: string enabled: boolean - showOnly: boolean + showOnly?: boolean topMessage: string timeToCountTo: number - informativeOnly: boolean + keepOnAfterCountdownOver: boolean imageUrl: string blurredImage: boolean } diff --git a/frontend/src/pages/countdown/countdown.page.tsx b/frontend/src/pages/countdown/countdown.page.tsx index 70651ea47..026bb954a 100644 --- a/frontend/src/pages/countdown/countdown.page.tsx +++ b/frontend/src/pages/countdown/countdown.page.tsx @@ -16,7 +16,7 @@ const CountdownPage = ({ children }: PropsWithChildren) => { return new Date() } }, [component]) - if (component?.enabled && component?.showOnly && (component?.informativeOnly || countTo.getTime() > Date.now())) { + if (component?.enabled && component?.showOnly && (component?.keepOnAfterCountdownOver || countTo.getTime() > Date.now())) { return (
BASICBASIC - -
ADMIN - -
SUPERUSER -