From 1b397b468ff327c50be1e2a776184b7a06886458 Mon Sep 17 00:00:00 2001 From: sezanzeb <28510156+sezanzeb@users.noreply.github.com> Date: Sat, 11 Apr 2026 12:29:18 +0200 Subject: [PATCH 01/12] Application dates configurable --- backend/src/controllers/dto.ts | 3 +++ backend/src/entities/application-settings.ts | 10 ++++++++-- backend/src/entities/settings.ts | 8 ++++++++ backend/src/services/project-service.ts | 2 +- backend/src/services/rating-service.ts | 4 ++-- backend/src/services/settings-service.ts | 10 +++++++++- frontend/src/components/pages/settings.tsx | 4 ++-- frontend/src/components/pages/status.tsx | 10 +++++++--- .../project-rating/rating-criteria-settings.tsx | 10 +++++----- 9 files changed, 45 insertions(+), 16 deletions(-) diff --git a/backend/src/controllers/dto.ts b/backend/src/controllers/dto.ts index b050f605..05e163bd 100644 --- a/backend/src/controllers/dto.ts +++ b/backend/src/controllers/dto.ts @@ -91,6 +91,9 @@ export class ApplicationSettingsDTO implements DTO { @IsNumber() @Expose() public hoursToConfirm!: number; +} + +export class ProjectSettingsDTO implements DTO { @IsBoolean() @Expose() public allowRatingProjects!: boolean; diff --git a/backend/src/entities/application-settings.ts b/backend/src/entities/application-settings.ts index d37586d6..40bc65cd 100644 --- a/backend/src/entities/application-settings.ts +++ b/backend/src/entities/application-settings.ts @@ -29,6 +29,12 @@ export class ApplicationSettings { public allowProfileFormUntil!: Date; @Column() public hoursToConfirm!: number; - @Column({ default: false }) - public allowRatingProjects!: boolean; + @Column() + public fillProfileFormFrom: Date; + @Column() + public fillProfileFormTo: Date; + @Column() + public acceptanceDeadline: Date; + @Column() + public confirmSpotUntil: Date; } diff --git a/backend/src/entities/settings.ts b/backend/src/entities/settings.ts index a7920725..8e9e387a 100644 --- a/backend/src/entities/settings.ts +++ b/backend/src/entities/settings.ts @@ -48,6 +48,11 @@ export class EmailSettings { public forgotPasswordEmail!: EmailTemplate; } +export class ProjectSettings { + @Column({ default: false }) + public allowRatingProjects!: boolean; +} + @Entity() export class Settings { @PrimaryGeneratedColumn() @@ -64,6 +69,9 @@ export class Settings { @Type(() => EmailSettings) @Column(() => EmailSettings) public email!: EmailSettings; + @Type(() => ProjectSettings) + @Column(() => ProjectSettings) + public rating!: ProjectSettings; } /** diff --git a/backend/src/services/project-service.ts b/backend/src/services/project-service.ts index 2d901904..f964bada 100644 --- a/backend/src/services/project-service.ts +++ b/backend/src/services/project-service.ts @@ -72,7 +72,7 @@ export class ProjectService implements IProjectService { .map((team) => team.id); const [settings] = await this._settings.find(); - const allowRatingProjects = settings.application.allowRatingProjects; + const allowRatingProjects = settings.project.allowRatingProjects; const isAdmin = user.role === UserRole.Root; const projects = await this._projects.find(); diff --git a/backend/src/services/rating-service.ts b/backend/src/services/rating-service.ts index 4cabd694..d858a061 100644 --- a/backend/src/services/rating-service.ts +++ b/backend/src/services/rating-service.ts @@ -236,9 +236,9 @@ export class RatingService implements IRatingService { } const settings = await this._settings.getSettings(); - if (!settings.application.allowRatingProjects) { + if (!settings.project.allowRatingProjects) { throw new ForbiddenError( - "Rating is not allowed due to application settings", + "Rating is not allowed due to settings", ); } diff --git a/backend/src/services/settings-service.ts b/backend/src/services/settings-service.ts index ea91129b..1fc97b12 100644 --- a/backend/src/services/settings-service.ts +++ b/backend/src/services/settings-service.ts @@ -115,10 +115,18 @@ export class SettingsService implements ISettingsService { applicationSettings.allowProfileFormFrom = new Date(); applicationSettings.allowProfileFormUntil = new Date(); applicationSettings.hoursToConfirm = 24; - applicationSettings.allowRatingProjects = false; return applicationSettings; } + /** + * Creates an application settings object with default values. + */ + private getDefaultProjectSettings(): ProjectSettings { + const projectSettings = new ProjectSettings(); + projectSettings.allowRatingProjects = false; + return projectSettings; + } + /** * Creates a form settings object with default values. */ diff --git a/frontend/src/components/pages/settings.tsx b/frontend/src/components/pages/settings.tsx index 2990adc2..c743cfa0 100644 --- a/frontend/src/components/pages/settings.tsx +++ b/frontend/src/components/pages/settings.tsx @@ -5,7 +5,7 @@ import { Heading } from "../base/headings"; import { ApplicationSettings } from "../settings/application/application-settings"; import { EmailSettings } from "../settings/mail-settings/email-settings"; import { FrontendSettings } from "../settings/appearance/frontend-settings"; -import { ProjectRatingSettings } from "../settings/project-rating/rating-criteria-settings"; +import { ProjectProjectSettings } from "../settings/project-rating/rating-criteria-settings"; import { SettingsSaveButton } from "../settings/save-button"; import { Page } from "./page"; import { SimpleCard } from "../base/simple-card"; @@ -40,7 +40,7 @@ export const Settings = () => ( - + ); diff --git a/frontend/src/components/pages/status.tsx b/frontend/src/components/pages/status.tsx index 0a5b1fab..6056b616 100644 --- a/frontend/src/components/pages/status.tsx +++ b/frontend/src/components/pages/status.tsx @@ -29,6 +29,10 @@ export const Status = () => { const { user, updateUser } = useLoginContext(); const confirmationDays = Math.floor(settings.application.hoursToConfirm / 24); + const fillProfileFormFrom = settings.application.fillProfileFormFrom; + const fillProfileFormTo = settings.application.fillProfileFormTo; + const acceptanceDeadline = settings.application.acceptanceDeadline; + const confirmSpotUntil = settings.application.confirmSpotUntil; const isExpired = user == null ? false : isConfirmationExpired(user); const isNotAttending = isExpired || user?.declined; const deadline = user?.confirmationExpiresAt; @@ -98,7 +102,7 @@ export const Status = () => { profile form - , any time between 01.03.2026 - 31.04.2026 + , any time between {fillProfileFormFrom} - {fillProfileFormTo} )} @@ -145,7 +149,7 @@ export const Status = () => { <> We will come back to you and send you a acceptance mail until{" "} - 01.05.2026. + {acceptanceDeadline}. )} @@ -173,7 +177,7 @@ export const Status = () => { <> If you got accepted, you need to confirm your spot until{" "} - 08.05.2026 + {confirmSpotUntil} {user?.admitted && ( <> {" "} diff --git a/frontend/src/components/settings/project-rating/rating-criteria-settings.tsx b/frontend/src/components/settings/project-rating/rating-criteria-settings.tsx index 3b6e01d9..67f0f2a4 100644 --- a/frontend/src/components/settings/project-rating/rating-criteria-settings.tsx +++ b/frontend/src/components/settings/project-rating/rating-criteria-settings.tsx @@ -71,7 +71,7 @@ const CriterionEditor = React.memo( /** * A component to edit criteria for rating projects. */ -export const ProjectRatingSettings = () => { +export const ProjectProjectSettings = () => { // Load all criteria and render them const [allCriteria, setAllCriteria] = useState([]); const [settings, setSettings] = useState>({}); @@ -91,7 +91,7 @@ export const ProjectRatingSettings = () => { useEffect(() => { // Only update if settings are loaded - if (settings.application) { + if (settings.rating) { api.updateSettings(settings as SettingsDTO); } }, [settings]); @@ -138,8 +138,8 @@ export const ProjectRatingSettings = () => { setSettings((prev) => { const changedSettings = { ...prev, - application: { - ...prev.application, + rating: { + ...prev.rating, allowRatingProjects: value, }, }; @@ -155,7 +155,7 @@ export const ProjectRatingSettings = () => { } From 278797eaad6bef043b339cacf3b048d535fa43b3 Mon Sep 17 00:00:00 2001 From: Tobi <28510156+sezanzeb@users.noreply.github.com> Date: Sat, 11 Apr 2026 12:35:44 +0200 Subject: [PATCH 02/12] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- frontend/src/components/pages/status.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/pages/status.tsx b/frontend/src/components/pages/status.tsx index 6056b616..fbab1667 100644 --- a/frontend/src/components/pages/status.tsx +++ b/frontend/src/components/pages/status.tsx @@ -29,10 +29,14 @@ export const Status = () => { const { user, updateUser } = useLoginContext(); const confirmationDays = Math.floor(settings.application.hoursToConfirm / 24); - const fillProfileFormFrom = settings.application.fillProfileFormFrom; - const fillProfileFormTo = settings.application.fillProfileFormTo; - const acceptanceDeadline = settings.application.acceptanceDeadline; - const confirmSpotUntil = settings.application.confirmSpotUntil; + const fillProfileFormFrom = dateToString( + settings.application.fillProfileFormFrom, + ); + const fillProfileFormTo = dateToString(settings.application.fillProfileFormTo); + const acceptanceDeadline = dateToString( + settings.application.acceptanceDeadline, + ); + const confirmSpotUntil = dateToString(settings.application.confirmSpotUntil); const isExpired = user == null ? false : isConfirmationExpired(user); const isNotAttending = isExpired || user?.declined; const deadline = user?.confirmationExpiresAt; From 93cfc6f048a7b9dfdd0634f7b8d71e21041c6828 Mon Sep 17 00:00:00 2001 From: Tobi <28510156+sezanzeb@users.noreply.github.com> Date: Sat, 11 Apr 2026 12:38:18 +0200 Subject: [PATCH 03/12] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../settings/project-rating/rating-criteria-settings.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/settings/project-rating/rating-criteria-settings.tsx b/frontend/src/components/settings/project-rating/rating-criteria-settings.tsx index 67f0f2a4..65e658d6 100644 --- a/frontend/src/components/settings/project-rating/rating-criteria-settings.tsx +++ b/frontend/src/components/settings/project-rating/rating-criteria-settings.tsx @@ -91,7 +91,7 @@ export const ProjectProjectSettings = () => { useEffect(() => { // Only update if settings are loaded - if (settings.rating) { + if (settings.project) { api.updateSettings(settings as SettingsDTO); } }, [settings]); @@ -138,8 +138,8 @@ export const ProjectProjectSettings = () => { setSettings((prev) => { const changedSettings = { ...prev, - rating: { - ...prev.rating, + project: { + ...prev.project, allowRatingProjects: value, }, }; From c6fcb10b364284ca9208e0463a399cf7b0e89a69 Mon Sep 17 00:00:00 2001 From: sezanzeb <28510156+sezanzeb@users.noreply.github.com> Date: Sat, 11 Apr 2026 12:41:20 +0200 Subject: [PATCH 04/12] wip --- backend/src/controllers/dto.ts | 17 +++++++++++++++++ backend/src/entities/application-settings.ts | 8 ++++---- backend/src/entities/settings.ts | 2 +- backend/src/services/settings-service.ts | 2 ++ frontend/src/components/pages/status.tsx | 4 ++-- .../project-rating/rating-criteria-settings.tsx | 2 +- 6 files changed, 27 insertions(+), 8 deletions(-) diff --git a/backend/src/controllers/dto.ts b/backend/src/controllers/dto.ts index 05e163bd..a3861fbd 100644 --- a/backend/src/controllers/dto.ts +++ b/backend/src/controllers/dto.ts @@ -34,6 +34,7 @@ import { EmailTemplateSize, FrontendSettings, Settings, + ProjectSettings, } from "../entities/settings"; import { User } from "../entities/user"; import { UserRole } from "../entities/user-role"; @@ -91,6 +92,22 @@ export class ApplicationSettingsDTO implements DTO { @IsNumber() @Expose() public hoursToConfirm!: number; + @Type(() => Date) + @IsDate() + @Expose() + public fillProfileFormFrom!: Date; + @Type(() => Date) + @IsDate() + @Expose() + public fillProfileFormUntil!: Date; + @Type(() => Date) + @IsDate() + @Expose() + public acceptanceDeadline!: Date; + @Type(() => Date) + @IsDate() + @Expose() + public confirmSpotUntil!: Date; } export class ProjectSettingsDTO implements DTO { diff --git a/backend/src/entities/application-settings.ts b/backend/src/entities/application-settings.ts index 40bc65cd..3d6f2e7b 100644 --- a/backend/src/entities/application-settings.ts +++ b/backend/src/entities/application-settings.ts @@ -30,11 +30,11 @@ export class ApplicationSettings { @Column() public hoursToConfirm!: number; @Column() - public fillProfileFormFrom: Date; + public fillProfileFormFrom!: Date; @Column() - public fillProfileFormTo: Date; + public fillProfileFormUntil!: Date; @Column() - public acceptanceDeadline: Date; + public acceptanceDeadline!: Date; @Column() - public confirmSpotUntil: Date; + public confirmSpotUntil!: Date; } diff --git a/backend/src/entities/settings.ts b/backend/src/entities/settings.ts index 8e9e387a..e4b6ca05 100644 --- a/backend/src/entities/settings.ts +++ b/backend/src/entities/settings.ts @@ -71,7 +71,7 @@ export class Settings { public email!: EmailSettings; @Type(() => ProjectSettings) @Column(() => ProjectSettings) - public rating!: ProjectSettings; + public project!: ProjectSettings; } /** diff --git a/backend/src/services/settings-service.ts b/backend/src/services/settings-service.ts index 1fc97b12..613363af 100644 --- a/backend/src/services/settings-service.ts +++ b/backend/src/services/settings-service.ts @@ -9,6 +9,7 @@ import { EmailTemplate, FrontendSettings, Settings, + ProjectSettings, } from "../entities/settings"; import { ConfigurationServiceToken, @@ -102,6 +103,7 @@ export class SettingsService implements ISettingsService { settings.application = this.getDefaultApplicationSettings(); settings.frontend = this.getDefaultFrontendSettings(); settings.email = this.getDefaultEmailSettings(); + settings.project = this.getDefaultProjectSettings(); return settings; } diff --git a/frontend/src/components/pages/status.tsx b/frontend/src/components/pages/status.tsx index 6056b616..c4e0806f 100644 --- a/frontend/src/components/pages/status.tsx +++ b/frontend/src/components/pages/status.tsx @@ -30,7 +30,7 @@ export const Status = () => { const confirmationDays = Math.floor(settings.application.hoursToConfirm / 24); const fillProfileFormFrom = settings.application.fillProfileFormFrom; - const fillProfileFormTo = settings.application.fillProfileFormTo; + const fillProfileFormUntil = settings.application.fillProfileFormUntil; const acceptanceDeadline = settings.application.acceptanceDeadline; const confirmSpotUntil = settings.application.confirmSpotUntil; const isExpired = user == null ? false : isConfirmationExpired(user); @@ -102,7 +102,7 @@ export const Status = () => { profile form - , any time between {fillProfileFormFrom} - {fillProfileFormTo} + , any time between {fillProfileFormFrom} - {fillProfileFormUntil} )} diff --git a/frontend/src/components/settings/project-rating/rating-criteria-settings.tsx b/frontend/src/components/settings/project-rating/rating-criteria-settings.tsx index 67f0f2a4..4ec6e062 100644 --- a/frontend/src/components/settings/project-rating/rating-criteria-settings.tsx +++ b/frontend/src/components/settings/project-rating/rating-criteria-settings.tsx @@ -91,7 +91,7 @@ export const ProjectProjectSettings = () => { useEffect(() => { // Only update if settings are loaded - if (settings.rating) { + if (settings.project) { api.updateSettings(settings as SettingsDTO); } }, [settings]); From d39cc834e82f9b8f05028e071b06a61ddd74c738 Mon Sep 17 00:00:00 2001 From: sezanzeb <28510156+sezanzeb@users.noreply.github.com> Date: Sat, 11 Apr 2026 13:30:24 +0200 Subject: [PATCH 05/12] wip --- backend/src/controllers/dto.ts | 12 ++++-------- backend/src/entities/application-settings.ts | 4 ---- backend/src/services/settings-service.ts | 2 ++ frontend/src/components/pages/status.tsx | 18 +++++++++++++----- frontend/src/util.ts | 6 +++++- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/backend/src/controllers/dto.ts b/backend/src/controllers/dto.ts index a3861fbd..dad2d324 100644 --- a/backend/src/controllers/dto.ts +++ b/backend/src/controllers/dto.ts @@ -95,14 +95,6 @@ export class ApplicationSettingsDTO implements DTO { @Type(() => Date) @IsDate() @Expose() - public fillProfileFormFrom!: Date; - @Type(() => Date) - @IsDate() - @Expose() - public fillProfileFormUntil!: Date; - @Type(() => Date) - @IsDate() - @Expose() public acceptanceDeadline!: Date; @Type(() => Date) @IsDate() @@ -186,6 +178,10 @@ export class SettingsDTO implements DTO> { @ValidateNested() @Expose() public email!: EmailSettingsDTO; + @Type(() => ProjectSettingsDTO) + @ValidateNested() + @Expose() + public project!: ProjectSettingsDTO; } export abstract class QuestionConfigurationDTOBase { diff --git a/backend/src/entities/application-settings.ts b/backend/src/entities/application-settings.ts index 3d6f2e7b..51c842f2 100644 --- a/backend/src/entities/application-settings.ts +++ b/backend/src/entities/application-settings.ts @@ -30,10 +30,6 @@ export class ApplicationSettings { @Column() public hoursToConfirm!: number; @Column() - public fillProfileFormFrom!: Date; - @Column() - public fillProfileFormUntil!: Date; - @Column() public acceptanceDeadline!: Date; @Column() public confirmSpotUntil!: Date; diff --git a/backend/src/services/settings-service.ts b/backend/src/services/settings-service.ts index 613363af..f0fbba11 100644 --- a/backend/src/services/settings-service.ts +++ b/backend/src/services/settings-service.ts @@ -117,6 +117,8 @@ export class SettingsService implements ISettingsService { applicationSettings.allowProfileFormFrom = new Date(); applicationSettings.allowProfileFormUntil = new Date(); applicationSettings.hoursToConfirm = 24; + applicationSettings.acceptanceDeadline = new Date(); + applicationSettings.confirmSpotUntil = new Date(); return applicationSettings; } diff --git a/frontend/src/components/pages/status.tsx b/frontend/src/components/pages/status.tsx index 0bbead0b..a68cd5ed 100644 --- a/frontend/src/components/pages/status.tsx +++ b/frontend/src/components/pages/status.tsx @@ -29,14 +29,22 @@ export const Status = () => { const { user, updateUser } = useLoginContext(); const confirmationDays = Math.floor(settings.application.hoursToConfirm / 24); - const fillProfileFormFrom = dateToString( - settings.application.fillProfileFormFrom, + + const allowProfileFormFrom = dateToString( + settings.application.allowProfileFormFrom, + ); + const allowProfileFormUntil = dateToString( + settings.application.allowProfileFormUntil, ); - const fillProfileFormTo = dateToString(settings.application.fillProfileFormTo); const acceptanceDeadline = dateToString( settings.application.acceptanceDeadline, ); - const confirmSpotUntil = dateToString(settings.application.confirmSpotUntil); + const confirmSpotUntil = dateToString( + settings.application.confirmSpotUntil, + ); + + console.log(settings.application); + const isExpired = user == null ? false : isConfirmationExpired(user); const isNotAttending = isExpired || user?.declined; const deadline = user?.confirmationExpiresAt; @@ -106,7 +114,7 @@ export const Status = () => { profile form - , any time between {fillProfileFormFrom} - {fillProfileFormUntil} + , any time between {allowProfileFormFrom} - {allowProfileFormUntil} )} diff --git a/frontend/src/util.ts b/frontend/src/util.ts index 9ee1b5ac..defd01f7 100644 --- a/frontend/src/util.ts +++ b/frontend/src/util.ts @@ -16,7 +16,11 @@ export const sleep = (ms: number) => * Formats a date "YYYY-MM-DD on HH:mm:ss" style. * @param date The date to format */ -export const dateToString = (date: Date) => { +export const dateToString = (date: Date | null) => { + if (date == null) { + return "?" + } + return date.toLocaleString("default", { year: "numeric", month: "long", From 0a6851a48c014d1b8051950dd014d9535ffe7355 Mon Sep 17 00:00:00 2001 From: sezanzeb <28510156+sezanzeb@users.noreply.github.com> Date: Sat, 11 Apr 2026 13:55:47 +0200 Subject: [PATCH 06/12] done --- frontend/src/api/index.ts | 6 ++ .../application/application-settings.tsx | 74 +++++++++++++------ 2 files changed, 58 insertions(+), 22 deletions(-) diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts index 09b2efcb..ea07a051 100644 --- a/frontend/src/api/index.ts +++ b/frontend/src/api/index.ts @@ -182,6 +182,12 @@ export class ApiClient { allowProfileFormUntil: this.reviveDate( settings.application.allowProfileFormUntil, ), + acceptanceDeadline: this.reviveDate( + settings.application.acceptanceDeadline, + ), + confirmSpotUntil: this.reviveDate( + settings.application.confirmSpotUntil, + ), }, }; } diff --git a/frontend/src/components/settings/application/application-settings.tsx b/frontend/src/components/settings/application/application-settings.tsx index b4a9c748..174b78a3 100644 --- a/frontend/src/components/settings/application/application-settings.tsx +++ b/frontend/src/components/settings/application/application-settings.tsx @@ -40,30 +40,24 @@ export const ApplicationSettings = () => { [settings], ); - const handleAllowProfileFormFromChange = useCallback( - (value: string) => { - setAllowProfileFormFrom(value); - const date = new Date(value); - - if (!isValidDate(date)) { - return; - } + const [allowProfileFormUntil, setAllowProfileFormUntil] = useDerivedState( + () => settings.application.allowProfileFormUntil.toISOString(), + [settings], + ); - updateApplicationSettings({ - allowProfileFormFrom: date, - }); - }, - [updateApplicationSettings], + const [acceptanceDeadline, setAcceptanceDeadline] = useDerivedState( + () => settings.application.acceptanceDeadline.toISOString(), + [settings], ); - const [allowProfileFormUntil, setAllowProfileFormUntil] = useDerivedState( - () => settings.application.allowProfileFormUntil.toISOString(), + const [confirmSpotUntil, setConfirmSpotUntil] = useDerivedState( + () => settings.application.confirmSpotUntil.toISOString(), [settings], ); - const handleAllowProfileFormUntilChange = useCallback( - (value: string) => { - setAllowProfileFormUntil(value); + const handleDateChange = useCallback( + (value: string, setter, key: string) => { + setter(value); const date = new Date(value); if (!isValidDate(date)) { @@ -71,7 +65,7 @@ export const ApplicationSettings = () => { } updateApplicationSettings({ - allowProfileFormUntil: date, + [key]: date, }); }, [updateApplicationSettings], @@ -112,11 +106,16 @@ export const ApplicationSettings = () => { placeholder="keep it fair, e.g. 240 for 10 days" /> - + + handleDateChange( + value, + setAllowProfileFormFrom, + "allowProfileFormFrom" + )} title="Open registration on" placeholder="1970-01-01 00:00:00" /> @@ -125,12 +124,43 @@ export const ApplicationSettings = () => { handleDateChange( + value, + setAllowProfileFormUntil, + "allowProfileFormUntil" + )} title="Close registration on" placeholder="1970-01-01 00:00:00" /> + + + handleDateChange( + value, + setAcceptanceDeadline, + "acceptanceDeadline" + )} + title="When we will accept people" + placeholder="1970-01-01 00:00:00" + /> + + + + handleDateChange( + value, + setConfirmSpotUntil, + "confirmSpotUntil" + )} + title="Until when accepted people need to confirm their spot" + placeholder="1970-01-01 00:00:00" + /> + + Use the add button to add new questions and the edit button in the top From d688a22e2d62c32ed295089271d261adc341f30c Mon Sep 17 00:00:00 2001 From: sezanzeb <28510156+sezanzeb@users.noreply.github.com> Date: Sat, 11 Apr 2026 14:01:50 +0200 Subject: [PATCH 07/12] lint stuff --- backend/src/services/rating-service.ts | 4 +- frontend/src/components/pages/status.tsx | 11 ++--- .../application/application-settings.tsx | 47 ++++++++++--------- frontend/src/util.ts | 2 +- 4 files changed, 33 insertions(+), 31 deletions(-) diff --git a/backend/src/services/rating-service.ts b/backend/src/services/rating-service.ts index d858a061..0ec8927a 100644 --- a/backend/src/services/rating-service.ts +++ b/backend/src/services/rating-service.ts @@ -237,9 +237,7 @@ export class RatingService implements IRatingService { const settings = await this._settings.getSettings(); if (!settings.project.allowRatingProjects) { - throw new ForbiddenError( - "Rating is not allowed due to settings", - ); + throw new ForbiddenError("Rating is not allowed due to settings"); } const project = await this._projects.findOneBy({ id: rating.project.id }); diff --git a/frontend/src/components/pages/status.tsx b/frontend/src/components/pages/status.tsx index a68cd5ed..a8c30ae7 100644 --- a/frontend/src/components/pages/status.tsx +++ b/frontend/src/components/pages/status.tsx @@ -39,11 +39,7 @@ export const Status = () => { const acceptanceDeadline = dateToString( settings.application.acceptanceDeadline, ); - const confirmSpotUntil = dateToString( - settings.application.confirmSpotUntil, - ); - - console.log(settings.application); + const confirmSpotUntil = dateToString(settings.application.confirmSpotUntil); const isExpired = user == null ? false : isConfirmationExpired(user); const isNotAttending = isExpired || user?.declined; @@ -114,7 +110,10 @@ export const Status = () => { profile form - , any time between {allowProfileFormFrom} - {allowProfileFormUntil} + , any time between{" "} + + {allowProfileFormFrom} - {allowProfileFormUntil} + )} diff --git a/frontend/src/components/settings/application/application-settings.tsx b/frontend/src/components/settings/application/application-settings.tsx index 174b78a3..7fb0d959 100644 --- a/frontend/src/components/settings/application/application-settings.tsx +++ b/frontend/src/components/settings/application/application-settings.tsx @@ -1,3 +1,4 @@ +import { Dispatch, SetStateAction } from "react"; import * as React from "react"; import { useCallback } from "react"; import type { ApplicationSettingsDTO } from "../../../api/types/dto"; @@ -56,7 +57,7 @@ export const ApplicationSettings = () => { ); const handleDateChange = useCallback( - (value: string, setter, key: string) => { + (value: string, setter: Dispatch>, key: string) => { setter(value); const date = new Date(value); @@ -111,11 +112,13 @@ export const ApplicationSettings = () => { handleDateChange( - value, - setAllowProfileFormFrom, - "allowProfileFormFrom" - )} + onChange={(value) => + handleDateChange( + value, + setAllowProfileFormFrom, + "allowProfileFormFrom", + ) + } title="Open registration on" placeholder="1970-01-01 00:00:00" /> @@ -124,11 +127,13 @@ export const ApplicationSettings = () => { handleDateChange( - value, - setAllowProfileFormUntil, - "allowProfileFormUntil" - )} + onChange={(value) => + handleDateChange( + value, + setAllowProfileFormUntil, + "allowProfileFormUntil", + ) + } title="Close registration on" placeholder="1970-01-01 00:00:00" /> @@ -138,11 +143,13 @@ export const ApplicationSettings = () => { handleDateChange( - value, - setAcceptanceDeadline, - "acceptanceDeadline" - )} + onChange={(value) => + handleDateChange( + value, + setAcceptanceDeadline, + "acceptanceDeadline", + ) + } title="When we will accept people" placeholder="1970-01-01 00:00:00" /> @@ -151,11 +158,9 @@ export const ApplicationSettings = () => { handleDateChange( - value, - setConfirmSpotUntil, - "confirmSpotUntil" - )} + onChange={(value) => + handleDateChange(value, setConfirmSpotUntil, "confirmSpotUntil") + } title="Until when accepted people need to confirm their spot" placeholder="1970-01-01 00:00:00" /> diff --git a/frontend/src/util.ts b/frontend/src/util.ts index defd01f7..e1a2797c 100644 --- a/frontend/src/util.ts +++ b/frontend/src/util.ts @@ -18,7 +18,7 @@ export const sleep = (ms: number) => */ export const dateToString = (date: Date | null) => { if (date == null) { - return "?" + return "?"; } return date.toLocaleString("default", { From b01409fece9dd2935cc2895b37e0b0d04376653e Mon Sep 17 00:00:00 2001 From: sezanzeb <28510156+sezanzeb@users.noreply.github.com> Date: Sat, 11 Apr 2026 14:03:29 +0200 Subject: [PATCH 08/12] Clarifying comment for ApplicationSettings --- backend/src/entities/application-settings.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/src/entities/application-settings.ts b/backend/src/entities/application-settings.ts index 51c842f2..1d2e13bf 100644 --- a/backend/src/entities/application-settings.ts +++ b/backend/src/entities/application-settings.ts @@ -11,6 +11,9 @@ import { FormSettings } from "./form-settings"; // TODO all other settings are part of the settings table, whereas ApplicationSettings // is a separate table. Move into settings table just like EmailSettings. +/** + * Application as in "Peoples application for the event" + */ @Entity() export class ApplicationSettings { @PrimaryGeneratedColumn() From 3dabbb116ded03bd2bd2c515402d28898ca00fa5 Mon Sep 17 00:00:00 2001 From: sezanzeb <28510156+sezanzeb@users.noreply.github.com> Date: Sat, 11 Apr 2026 14:13:09 +0200 Subject: [PATCH 09/12] Fix tests --- backend/test/services/mock/mock-settings-service.ts | 4 ++++ .../project-service-get-all-projects.spec.ts | 6 +++--- backend/test/services/rating-service.spec.ts | 12 ++++++------ 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/backend/test/services/mock/mock-settings-service.ts b/backend/test/services/mock/mock-settings-service.ts index 921fd0fe..d8dc7683 100644 --- a/backend/test/services/mock/mock-settings-service.ts +++ b/backend/test/services/mock/mock-settings-service.ts @@ -25,7 +25,11 @@ export const defaultSettings = { }, allowProfileFormFrom: new Date(), allowProfileFormUntil: new Date(), + acceptanceDeadline: new Date(), + confirmSpotUntil: new Date(), hoursToConfirm: 24, + }, + project: { allowRatingProjects: false, }, frontend: { diff --git a/backend/test/services/project-service-get-all-projects.spec.ts b/backend/test/services/project-service-get-all-projects.spec.ts index d3843a76..a1a57a87 100644 --- a/backend/test/services/project-service-get-all-projects.spec.ts +++ b/backend/test/services/project-service-get-all-projects.spec.ts @@ -56,8 +56,8 @@ describe(ProjectService.name, () => { await settingsRepo.save([ { ...defaultSettings, - application: { - ...defaultSettings.application, + project: { + ...defaultSettings.project, allowRatingProjects: false, }, }, @@ -71,7 +71,7 @@ describe(ProjectService.name, () => { const allowRatingProjects = async (value: boolean): Promise => { const settingsRepo = database.getRepository(Settings); const settings = { - application: { + project: { allowRatingProjects: value, }, }; diff --git a/backend/test/services/rating-service.spec.ts b/backend/test/services/rating-service.spec.ts index 544afe39..1c10411c 100644 --- a/backend/test/services/rating-service.spec.ts +++ b/backend/test/services/rating-service.spec.ts @@ -121,7 +121,7 @@ describe("RatingService", () => { expect.assertions(1); settingsService.mocks.getSettings.mockResolvedValue({ - application: { allowRatingProjects: false }, + project: { allowRatingProjects: false }, } as any); const rating = Object.assign(new Rating(), { @@ -140,7 +140,7 @@ describe("RatingService", () => { expect.assertions(1); settingsService.mocks.getSettings.mockResolvedValue({ - application: { allowRatingProjects: true }, + project: { allowRatingProjects: true }, } as any); const rating = Object.assign(new Rating(), { @@ -159,7 +159,7 @@ describe("RatingService", () => { expect.assertions(1); settingsService.mocks.getSettings.mockResolvedValue({ - application: { allowRatingProjects: true }, + project: { allowRatingProjects: true }, } as any); await projectRepo.update(mockProject.id, { allowRating: false }); @@ -181,7 +181,7 @@ describe("RatingService", () => { expect.assertions(1); settingsService.mocks.getSettings.mockResolvedValue({ - application: { allowRatingProjects: true }, + project: { allowRatingProjects: true }, } as any); const rating = Object.assign(new Rating(), { @@ -200,7 +200,7 @@ describe("RatingService", () => { expect.assertions(2); settingsService.mocks.getSettings.mockResolvedValue({ - application: { allowRatingProjects: true }, + project: { allowRatingProjects: true }, } as any); const rating = Object.assign(new Rating(), { @@ -220,7 +220,7 @@ describe("RatingService", () => { expect.assertions(1); settingsService.mocks.getSettings.mockResolvedValue({ - application: { allowRatingProjects: true }, + project: { allowRatingProjects: true }, } as any); const rating = Object.assign(new Rating(), { From c1d62ca88172de62f7ae96f36c772fb148b24b12 Mon Sep 17 00:00:00 2001 From: sezanzeb <28510156+sezanzeb@users.noreply.github.com> Date: Sat, 11 Apr 2026 14:27:39 +0200 Subject: [PATCH 10/12] stuff --- backend/src/entities/application-settings.ts | 4 ++-- backend/src/services/settings-service.ts | 2 +- .../settings/project-rating/rating-criteria-settings.tsx | 2 +- frontend/src/util.ts | 6 +----- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/backend/src/entities/application-settings.ts b/backend/src/entities/application-settings.ts index 1d2e13bf..c24ba29e 100644 --- a/backend/src/entities/application-settings.ts +++ b/backend/src/entities/application-settings.ts @@ -32,8 +32,8 @@ export class ApplicationSettings { public allowProfileFormUntil!: Date; @Column() public hoursToConfirm!: number; - @Column() + @Column({ default: new Date() }) public acceptanceDeadline!: Date; - @Column() + @Column({ default: new Date() }) public confirmSpotUntil!: Date; } diff --git a/backend/src/services/settings-service.ts b/backend/src/services/settings-service.ts index f0fbba11..8f1fe9d9 100644 --- a/backend/src/services/settings-service.ts +++ b/backend/src/services/settings-service.ts @@ -123,7 +123,7 @@ export class SettingsService implements ISettingsService { } /** - * Creates an application settings object with default values. + * Creates a project settings object with default values. */ private getDefaultProjectSettings(): ProjectSettings { const projectSettings = new ProjectSettings(); diff --git a/frontend/src/components/settings/project-rating/rating-criteria-settings.tsx b/frontend/src/components/settings/project-rating/rating-criteria-settings.tsx index 65e658d6..2bd02644 100644 --- a/frontend/src/components/settings/project-rating/rating-criteria-settings.tsx +++ b/frontend/src/components/settings/project-rating/rating-criteria-settings.tsx @@ -155,7 +155,7 @@ export const ProjectProjectSettings = () => { } diff --git a/frontend/src/util.ts b/frontend/src/util.ts index e1a2797c..9ee1b5ac 100644 --- a/frontend/src/util.ts +++ b/frontend/src/util.ts @@ -16,11 +16,7 @@ export const sleep = (ms: number) => * Formats a date "YYYY-MM-DD on HH:mm:ss" style. * @param date The date to format */ -export const dateToString = (date: Date | null) => { - if (date == null) { - return "?"; - } - +export const dateToString = (date: Date) => { return date.toLocaleString("default", { year: "numeric", month: "long", From 76392e7df5e33ced722b473aa6bd610e1eff61e8 Mon Sep 17 00:00:00 2001 From: sezanzeb <28510156+sezanzeb@users.noreply.github.com> Date: Sat, 11 Apr 2026 14:33:09 +0200 Subject: [PATCH 11/12] fix default value for dates --- backend/src/entities/application-settings.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/entities/application-settings.ts b/backend/src/entities/application-settings.ts index c24ba29e..6dd0dc66 100644 --- a/backend/src/entities/application-settings.ts +++ b/backend/src/entities/application-settings.ts @@ -32,8 +32,8 @@ export class ApplicationSettings { public allowProfileFormUntil!: Date; @Column() public hoursToConfirm!: number; - @Column({ default: new Date() }) + @Column({ default: () => "CURRENT_TIMESTAMP" }) public acceptanceDeadline!: Date; - @Column({ default: new Date() }) + @Column({ default: () => "CURRENT_TIMESTAMP" }) public confirmSpotUntil!: Date; } From f76c6c229f8ec39ccb71c107661664494e7ded28 Mon Sep 17 00:00:00 2001 From: sezanzeb <28510156+sezanzeb@users.noreply.github.com> Date: Sat, 11 Apr 2026 14:35:33 +0200 Subject: [PATCH 12/12] review --- frontend/src/components/pages/settings.tsx | 4 ++-- .../settings/project-rating/rating-criteria-settings.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/pages/settings.tsx b/frontend/src/components/pages/settings.tsx index c743cfa0..2990adc2 100644 --- a/frontend/src/components/pages/settings.tsx +++ b/frontend/src/components/pages/settings.tsx @@ -5,7 +5,7 @@ import { Heading } from "../base/headings"; import { ApplicationSettings } from "../settings/application/application-settings"; import { EmailSettings } from "../settings/mail-settings/email-settings"; import { FrontendSettings } from "../settings/appearance/frontend-settings"; -import { ProjectProjectSettings } from "../settings/project-rating/rating-criteria-settings"; +import { ProjectRatingSettings } from "../settings/project-rating/rating-criteria-settings"; import { SettingsSaveButton } from "../settings/save-button"; import { Page } from "./page"; import { SimpleCard } from "../base/simple-card"; @@ -40,7 +40,7 @@ export const Settings = () => ( - + ); diff --git a/frontend/src/components/settings/project-rating/rating-criteria-settings.tsx b/frontend/src/components/settings/project-rating/rating-criteria-settings.tsx index 2bd02644..2d8d6a41 100644 --- a/frontend/src/components/settings/project-rating/rating-criteria-settings.tsx +++ b/frontend/src/components/settings/project-rating/rating-criteria-settings.tsx @@ -71,7 +71,7 @@ const CriterionEditor = React.memo( /** * A component to edit criteria for rating projects. */ -export const ProjectProjectSettings = () => { +export const ProjectRatingSettings = () => { // Load all criteria and render them const [allCriteria, setAllCriteria] = useState([]); const [settings, setSettings] = useState>({});