From 475b932f9d0ec029ada844072e9d89bebd4e902c Mon Sep 17 00:00:00 2001 From: Elias Schneider Date: Tue, 13 Aug 2024 20:51:10 +0200 Subject: [PATCH] feat: add option to change session duration --- backend/internal/common/config.go | 5 +++ backend/internal/common/jwt.go | 4 +- .../handler/application_configuration.go | 40 +++++++++++-------- .../model/application_configuration.go | 1 + frontend/src/lib/components/form-input.svelte | 23 +++++++---- .../components/header/header-avatar.svelte | 7 ++-- .../application-configuration-service.ts | 12 +++--- .../lib/types/application-configuration.ts | 1 + .../application-configuration/+page.server.ts | 2 +- .../application-configuration-form.svelte | 26 +++++++++--- .../tests/application-configuration.spec.ts | 1 + 11 files changed, 79 insertions(+), 43 deletions(-) diff --git a/backend/internal/common/config.go b/backend/internal/common/config.go index d1262ac..6762e59 100644 --- a/backend/internal/common/config.go +++ b/backend/internal/common/config.go @@ -36,6 +36,11 @@ func NewDefaultDbConfig() model.ApplicationConfiguration { IsPublic: true, Value: "Pocket ID", }, + SessionDuration: model.ApplicationConfigurationVariable{ + Key: "sessionDuration", + Type: "number", + Value: "60", + }, BackgroundImageType: model.ApplicationConfigurationVariable{ Key: "backgroundImageType", Type: "string", diff --git a/backend/internal/common/jwt.go b/backend/internal/common/jwt.go index 41e4490..8a4586e 100644 --- a/backend/internal/common/jwt.go +++ b/backend/internal/common/jwt.go @@ -15,6 +15,7 @@ import ( "os" "path/filepath" "slices" + "strconv" "strings" "time" ) @@ -73,10 +74,11 @@ func GenerateIDToken(user model.User, clientID string, scope string, nonce strin // GenerateAccessToken generates an access token for the given user. func GenerateAccessToken(user model.User) (tokenString string, err error) { + sessionDurationInMinutes, _ := strconv.Atoi(DbConfig.SessionDuration.Value) claim := accessTokenJWTClaims{ RegisteredClaims: jwt.RegisteredClaims{ Subject: user.ID, - ExpiresAt: jwt.NewNumericDate(time.Now().Add(1 * time.Hour)), + ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(sessionDurationInMinutes) * time.Minute)), IssuedAt: jwt.NewNumericDate(time.Now()), Audience: jwt.ClaimStrings{utils.GetHostFromURL(EnvConfig.AppURL)}, }, diff --git a/backend/internal/handler/application_configuration.go b/backend/internal/handler/application_configuration.go index c952059..62a3efc 100644 --- a/backend/internal/handler/application_configuration.go +++ b/backend/internal/handler/application_configuration.go @@ -16,6 +16,7 @@ import ( func RegisterConfigurationRoutes(group *gin.RouterGroup) { group.GET("/application-configuration", listApplicationConfigurationHandler) + group.GET("/application-configuration/all", middleware.JWTAuth(true), listAllApplicationConfigurationHandler) group.PUT("/application-configuration", updateApplicationConfigurationHandler) group.GET("/application-configuration/logo", getLogoHandler) @@ -27,24 +28,11 @@ func RegisterConfigurationRoutes(group *gin.RouterGroup) { } func listApplicationConfigurationHandler(c *gin.Context) { - // Return also the private configuration variables if the user is admin and showAll is true - showAll := c.GetBool("userIsAdmin") && c.DefaultQuery("showAll", "false") == "true" + listApplicationConfiguration(c, false) +} - var configuration []model.ApplicationConfigurationVariable - var err error - - if showAll { - err = common.DB.Find(&configuration).Error - } else { - err = common.DB.Find(&configuration, "is_public = true").Error - } - - if err != nil { - utils.UnknownHandlerError(c, err) - return - } - - c.JSON(200, configuration) +func listAllApplicationConfigurationHandler(c *gin.Context) { + listApplicationConfiguration(c, true) } func updateApplicationConfigurationHandler(c *gin.Context) { @@ -188,3 +176,21 @@ func updateImage(c *gin.Context, imageName string, oldImageType string) { c.Status(http.StatusNoContent) } + +func listApplicationConfiguration(c *gin.Context, showAll bool) { + var configuration []model.ApplicationConfigurationVariable + var err error + + if showAll { + err = common.DB.Find(&configuration).Error + } else { + err = common.DB.Find(&configuration, "is_public = true").Error + } + + if err != nil { + utils.UnknownHandlerError(c, err) + return + } + + c.JSON(200, configuration) +} diff --git a/backend/internal/model/application_configuration.go b/backend/internal/model/application_configuration.go index fe244e7..b7a464d 100644 --- a/backend/internal/model/application_configuration.go +++ b/backend/internal/model/application_configuration.go @@ -12,6 +12,7 @@ type ApplicationConfiguration struct { AppName ApplicationConfigurationVariable BackgroundImageType ApplicationConfigurationVariable LogoImageType ApplicationConfigurationVariable + SessionDuration ApplicationConfigurationVariable } type ApplicationConfigurationUpdateDto struct { diff --git a/frontend/src/lib/components/form-input.svelte b/frontend/src/lib/components/form-input.svelte index a285288..5424e01 100644 --- a/frontend/src/lib/components/form-input.svelte +++ b/frontend/src/lib/components/form-input.svelte @@ -7,10 +7,12 @@ let { input = $bindable(), label, + description, children }: { input: FormInput; label: string; + description?: string; children?: Snippet; } = $props(); @@ -18,13 +20,18 @@
- - {#if children} - {@render children()} - {:else} - - {/if} - {#if input.error} -

{input.error}

+ + {#if description} +

{description}

{/if} +
+ {#if children} + {@render children()} + {:else} + + {/if} + {#if input.error} +

{input.error}

+ {/if} +
diff --git a/frontend/src/lib/components/header/header-avatar.svelte b/frontend/src/lib/components/header/header-avatar.svelte index 11c55a1..d7ff792 100644 --- a/frontend/src/lib/components/header/header-avatar.svelte +++ b/frontend/src/lib/components/header/header-avatar.svelte @@ -1,5 +1,4 @@ @@ -31,7 +30,7 @@ {$userStore?.firstName} {$userStore?.lastName}

-

{$userStore?.email}

+

{$userStore?.email}

diff --git a/frontend/src/lib/services/application-configuration-service.ts b/frontend/src/lib/services/application-configuration-service.ts index e517fe1..d384f8e 100644 --- a/frontend/src/lib/services/application-configuration-service.ts +++ b/frontend/src/lib/services/application-configuration-service.ts @@ -6,12 +6,12 @@ import APIService from './api-service'; export default class ApplicationConfigurationService extends APIService { async list(showAll = false) { - const { data } = await this.api.get( - '/application-configuration', - { - params: { showAll } - } - ); + let url = '/application-configuration'; + if (showAll) { + url += '/all'; + } + + const { data } = await this.api.get(url); const applicationConfiguration: Partial = {}; data.forEach(({ key, value }) => { diff --git a/frontend/src/lib/types/application-configuration.ts b/frontend/src/lib/types/application-configuration.ts index 3f56689..59cd45f 100644 --- a/frontend/src/lib/types/application-configuration.ts +++ b/frontend/src/lib/types/application-configuration.ts @@ -1,6 +1,7 @@ export type AllApplicationConfiguration = { appName: string; + sessionDuration: string; }; export type ApplicationConfiguration = AllApplicationConfiguration; diff --git a/frontend/src/routes/settings/admin/application-configuration/+page.server.ts b/frontend/src/routes/settings/admin/application-configuration/+page.server.ts index ab3c001..0c30081 100644 --- a/frontend/src/routes/settings/admin/application-configuration/+page.server.ts +++ b/frontend/src/routes/settings/admin/application-configuration/+page.server.ts @@ -5,6 +5,6 @@ export const load: PageServerLoad = async ({ cookies }) => { const applicationConfigurationService = new ApplicationConfigurationService( cookies.get('access_token') ); - const applicationConfiguration = await applicationConfigurationService.list(); + const applicationConfiguration = await applicationConfigurationService.list(true); return { applicationConfiguration }; }; diff --git a/frontend/src/routes/settings/admin/application-configuration/application-configuration-form.svelte b/frontend/src/routes/settings/admin/application-configuration/application-configuration-form.svelte index cb64ae7..2791b07 100644 --- a/frontend/src/routes/settings/admin/application-configuration/application-configuration-form.svelte +++ b/frontend/src/routes/settings/admin/application-configuration/application-configuration-form.svelte @@ -16,11 +16,21 @@ let isLoading = $state(false); const updatedApplicationConfiguration: AllApplicationConfiguration = { - appName: applicationConfiguration.appName + appName: applicationConfiguration.appName, + sessionDuration: applicationConfiguration.sessionDuration }; const formSchema = z.object({ - appName: z.string().min(2).max(30) + appName: z.string().min(2).max(30), + sessionDuration: z.string().refine( + (val) => { + const num = Number(val); + return Number.isInteger(num) && num >= 1 && num <= 43200; + }, + { + message: 'Session duration must be between 1 and 43200 minutes' + } + ) }); type FormSchema = typeof formSchema; @@ -35,10 +45,14 @@
-
-
- -
+
+ + +
diff --git a/frontend/tests/application-configuration.spec.ts b/frontend/tests/application-configuration.spec.ts index b021346..0cd519a 100644 --- a/frontend/tests/application-configuration.spec.ts +++ b/frontend/tests/application-configuration.spec.ts @@ -7,6 +7,7 @@ test('Update general configuration', async ({ page }) => { await page.goto('/settings/admin/application-configuration'); await page.getByLabel('Name').fill('Updated Name'); + await page.getByLabel('Session Duration').fill('30'); await page.getByRole('button', { name: 'Save' }).first().click(); await expect(page.getByTestId('application-name')).toHaveText('Updated Name');