Skip to content

Commit

Permalink
Make forced countdown optional based on role
Browse files Browse the repository at this point in the history
  • Loading branch information
Isti01 committed Sep 1, 2024
1 parent 36e4b01 commit f83c944
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ class MinRoleSettingProxy(
defaultValue: String,
fieldName: String = "",
description: String = "",
minRoleToEdit: RoleType = RoleType.STAFF
minRoleToEdit: RoleType = RoleType.STAFF,
val grantedForRoles: List<String> = listOf(RoleType.ADMIN.name, RoleType.SUPERUSER.name)
) : SettingProxy(
componentPropertyService, component, property,
defaultValue = defaultValue, type = SettingType.MIN_ROLE,
Expand All @@ -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)
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
@@ -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)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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 = ""
Expand Down
31 changes: 7 additions & 24 deletions backend/src/main/resources/templates/componentSettings.html
Original file line number Diff line number Diff line change
Expand Up @@ -455,36 +455,19 @@ <h4 th:text="${input.fieldName}" th:id="|_${input.property}|">Group Name</h4>
<span class="note" th:text="${input.description}" style="margin-bottom: 20px;"></span>

<table>
<tr th:each="role : ${T(hu.bme.sch.cmsch.model.RoleType).values()}"
th:if="${role.value < T(hu.bme.sch.cmsch.model.RoleType).ADMIN.value}">
<tr th:each="role : ${T(hu.bme.sch.cmsch.component.MinRoleSettingProxy).Companion.ALL_POSSIBLE_ROLES}">

<td th:text="${role.name()}">BASIC</td>
<td th:text="${role.name()}" th:class="${input.grantedForRoles.contains(role.name()) ? 'disabled' : ''}">BASIC</td>
<td>
<label class="switch"
<label th:class="|switch ${input.grantedForRoles.contains(role.name()) ? 'disabled' : ''}|"
th:data-param1="${input.property}" th:data-param2="${role.name()}"
th:onclick="|changeRoleField(this.getAttribute('data-param1'), this.getAttribute('data-param2'))|">
<input type="checkbox"
th:disabled="${input.grantedForRoles.contains(role.name())}"
th:checked="${input.grantedForRoles.contains(role.name())}"
th:name="|${input.property}_${role.name()}|"
th:id="|${input.property}_${role.name()}|"/>
<span class="slider"></span>
</label>
</td>
</tr>
<tr>
<td th:text="${T(hu.bme.sch.cmsch.model.RoleType).ADMIN.name()}" class="disabled">ADMIN</td>
<td>
<label class="switch disabled">
<input type="checkbox" th:name="|${input.property}_ADMIN|" checked disabled />
<span class="slider disabled"></span>
</label>
</td>
</tr>
<tr>
<td th:text="${T(hu.bme.sch.cmsch.model.RoleType).SUPERUSER.name()}" class="disabled">SUPERUSER</td>
<td>
<label class="switch disabled">
<input type="checkbox" th:name="|${input.property}_SUPERUSER|" checked disabled />
<span class="slider disabled"></span>
th:id="|${input.property}_${role.name()}${input.grantedForRoles.contains(role.name()) ? '_' : ''}|"/>
<span th:class="|slider ${input.grantedForRoles.contains(role.name()) ? 'disabled' : ''}|"></span>
</label>
</td>
</tr>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/api/contexts/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/countdown/countdown.page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<Flex h="100%" w="100%">
<Helmet title={component?.title} />
Expand Down

0 comments on commit f83c944

Please sign in to comment.