├── .nvmrc ├── .cache ├── npm │ ├── .gitkeep │ └── sentry-cli │ │ └── .gitkeep └── composer │ └── .gitkeep ├── api ├── config │ ├── jwt │ │ └── .gitkeep │ ├── packages │ │ ├── test │ │ │ ├── mailer.yaml │ │ │ ├── hautelook_alice.yaml │ │ │ ├── doctrine_migrations.yaml │ │ │ ├── nelmio_alice.yaml │ │ │ ├── routing.yaml │ │ │ ├── validator.yaml │ │ │ ├── doctrine.yaml │ │ │ ├── web_profiler.yaml │ │ │ ├── http_cache.yaml │ │ │ └── monolog.yaml │ │ ├── dev │ │ │ ├── mailer.yaml │ │ │ ├── routing.yaml │ │ │ ├── doctrine.yaml │ │ │ ├── web_profiler.yaml │ │ │ ├── nelmio_alice.yaml │ │ │ ├── debug.yaml │ │ │ └── monolog.yaml │ │ ├── prod │ │ │ ├── mailer.yaml │ │ │ ├── api_platform.yaml │ │ │ ├── deprecations.yaml │ │ │ ├── doctrine.yaml │ │ │ └── monolog.yaml │ │ ├── twig.yaml │ │ ├── translation.yaml │ │ ├── validator.yaml │ │ ├── routing.yaml │ │ ├── gesdinet_jwt_refresh_token.yaml │ │ ├── stof_doctrine_extensions.yaml │ │ └── nelmio_cors.yaml │ ├── routes │ │ ├── api_platform.yaml │ │ ├── framework.yaml │ │ ├── annotations.yaml │ │ └── dev │ │ │ └── web_profiler.yaml │ ├── preload.php │ └── routes.yaml ├── fixtures │ └── .gitignore ├── migrations │ ├── .gitignore │ ├── empty-data │ │ └── .gitkeep │ ├── schema │ │ ├── checklists │ │ │ └── helpers.php │ │ └── Version20250412165829.php │ ├── prod-data │ │ └── helpers.php │ └── dev-data │ │ ├── Version202201230531.php │ │ ├── Version202202051218.php │ │ ├── Version202211261414.php │ │ ├── Version202305011841.php │ │ ├── Version202305092233.php │ │ ├── Version202306250019.php │ │ ├── Version202308081601.php │ │ ├── Version202309300329.php │ │ ├── Version202311121726.php │ │ ├── Version202311121824.php │ │ ├── Version202311261457.php │ │ ├── Version202312032018.php │ │ ├── Version202404012013.php │ │ ├── Version202404031358.php │ │ ├── Version202404121950.php │ │ ├── Version202209110752PM.php │ │ ├── Version202409282339.php │ │ ├── Version202410111836.php │ │ ├── Version202504121559.php │ │ ├── Version202409282323.php │ │ ├── Version202504130046.php │ │ ├── Version202504252112.php │ │ ├── Version202505151020.php │ │ ├── Version202505202216.php │ │ ├── Version202406211251.php │ │ └── Version202409281917.php ├── src │ ├── Controller │ │ └── .gitignore │ ├── Repository │ │ ├── .gitignore │ │ └── CanFilterByUserInterface.php │ ├── Entity │ │ ├── SupportsContentNodeChildren.php │ │ ├── HasId.php │ │ ├── BelongsToCampInterface.php │ │ ├── HasParentInterface.php │ │ ├── CopyFromPrototypeInterface.php │ │ ├── SortableEntityInterface.php │ │ ├── BelongsToContentNodeTreeInterface.php │ │ ├── RefreshToken.php │ │ ├── Languages.php │ │ ├── UserCamp.php │ │ └── CampRootContentNode.php │ ├── InputFilter │ │ ├── UnexpectedValueException.php │ │ ├── InvalidOptionsException.php │ │ ├── CleanText.php │ │ └── Trim.php │ ├── Serializer │ │ ├── Normalizer │ │ │ ├── UnsupportedRelationException.php │ │ │ ├── Error │ │ │ │ └── TranslationInfo.php │ │ │ └── RelatedCollectionLink.php │ │ └── NoCachingSupportTrait.php │ ├── Validator │ │ ├── AssertNoLoop.php │ │ ├── ContentNode │ │ │ ├── AssertNoRootChange.php │ │ │ ├── AssertAttachedToRoot.php │ │ │ └── AssertContentTypeCompatible.php │ │ ├── ChecklistItem │ │ │ ├── AssertBelongsToSameCamp.php │ │ │ └── AssertBelongsToSameChecklist.php │ │ ├── Period │ │ │ ├── AssertGreaterThanOrEqualToLastScheduleEntryEnd.php │ │ │ ├── AssertLessThanOrEqualToEarliestScheduleEntryStart.php │ │ │ └── AssertNotOverlappingWithOtherPeriods.php │ │ ├── AssertContainsAtLeastOneManager.php │ │ ├── MaterialItemUpdateGroupSequence.php │ │ ├── ScheduleEntryPostGroupSequence.php │ │ └── ColumnLayout │ │ │ ├── AssertColumWidthsSumTo12.php │ │ │ └── AssertNoOrphanChildren.php │ ├── Util │ │ ├── DateTimeUtil.php │ │ ├── ParametrizedTestHelper.php │ │ └── IdGenerator.php │ ├── HttpCache │ │ └── CanGenerateTagsInterface.php │ ├── Kernel.php │ ├── State │ │ └── CampCollaborationSendEmailTrait.php │ └── Doctrine │ │ └── NameSpaceIgnoringVersionComparator.php ├── translations │ ├── validators.rm.yml │ ├── validators.de_CH.yml │ ├── validators.de_CH_scout.yml │ ├── validators.en_CH_scout.yml │ ├── validators.fr_CH_scout.yml │ ├── validators.it_CH_scout.yml │ ├── validators.rm_CH_scout.yml │ ├── email+intl-icu.en.json │ ├── email+intl-icu.de.json │ └── validators.en.yml ├── public │ ├── favicon.ico │ └── index.php ├── docker │ ├── varnish │ │ └── vcl │ │ │ └── _config.vcl │ └── php │ │ └── conf.d │ │ ├── api-platform.prod.ini │ │ ├── api-platform.ini │ │ └── api-platform.dev.ini ├── phpstan.neon ├── .coveralls.yml ├── templates │ └── emails │ │ ├── userActivation.en.text.twig │ │ ├── userActivation.de.text.twig │ │ ├── passwordResetLink.en.text.twig │ │ ├── passwordResetLink.de.text.twig │ │ ├── campCollaborationInvite.en.text.twig │ │ ├── campCollaborationInvite.de.text.twig │ │ ├── verifyMailAdress.en.text.twig │ │ ├── verifyMailAdress.de.text.twig │ │ ├── userActivation.en.html.twig │ │ ├── button.twig │ │ └── userActivation.de.html.twig ├── .vscode │ └── settings.json ├── tests │ ├── State │ │ ├── Util │ │ │ └── MockableClosure.php │ │ └── CampCollaborationTestTrait.php │ ├── Api │ │ ├── SnapshotTests │ │ │ └── __snapshots__ │ │ │ │ ├── ResponseSnapshotTest__testGetItemMatchesStructure with data set content_types__1.json │ │ │ │ ├── ResponseSnapshotTest__testGetItemMatchesStructure with data set activity_progress_labels__1.json │ │ │ │ ├── ResponseSnapshotTest__testGetItemMatchesStructure with data set day_responsibles__1.json │ │ │ │ ├── ResponseSnapshotTest__testGetItemMatchesStructure with data set activity_responsibles__1.json │ │ │ │ ├── ResponseSnapshotTest__testGetItemMatchesStructure with data set checklists__1.json │ │ │ │ ├── ResponseSnapshotTest__testGetItemMatchesStructure with data set material_lists__1.json │ │ │ │ ├── ResponseSnapshotTest__testGetItemMatchesStructure with data set checklist_items__1.json │ │ │ │ └── ResponseSnapshotTest__testGetItemMatchesStructure with data set comments__1.json │ │ ├── Profiles │ │ │ └── CreateProfileTest.php │ │ ├── ContentNodes │ │ │ ├── ContentNode │ │ │ │ ├── CreateContentNodeTest.php │ │ │ │ └── DeleteContentNodeTest.php │ │ │ └── MaterialNode │ │ │ │ └── CreateMaterialNodeTest.php │ │ ├── Days │ │ │ ├── DeleteDayTest.php │ │ │ ├── CreateDayTest.php │ │ │ └── UpdateDayTest.php │ │ ├── ContentTypes │ │ │ ├── DeleteContentTypeTest.php │ │ │ └── CreateContentTypeTest.php │ │ ├── Comments │ │ │ └── UpdateCommentTest.php │ │ └── Invitations │ │ │ └── DeleteInvitationTest.php │ ├── bootstrap.php │ └── HttpCache │ │ └── Entity │ │ ├── NotAResource.php │ │ ├── ContainNonResource.php │ │ ├── DummyNoGetOperation.php │ │ ├── BaseEntity.php │ │ └── RelatedDummy.php ├── .env.test ├── .gitignore └── .dockerignore ├── pdf ├── common ├── src │ ├── renderer │ │ ├── styleStore.js │ │ └── __tests__ │ │ │ ├── SimpleDocument.vue │ │ │ └── createCircularReplacer.js │ ├── assets │ │ └── fonts │ │ │ └── Inter │ │ │ ├── InterDisplay-Bold.ttf │ │ │ ├── InterDisplay-Italic.ttf │ │ │ ├── InterDisplay-Medium.ttf │ │ │ ├── InterDisplay-Regular.ttf │ │ │ ├── InterDisplay-SemiBold.ttf │ │ │ └── InterDisplay-BoldItalic.ttf │ ├── campPrint │ │ ├── helpers.js │ │ ├── picasso │ │ │ └── longestTime.js │ │ ├── tableOfContents │ │ │ ├── entry │ │ │ │ ├── Summary.vue │ │ │ │ ├── Story.vue │ │ │ │ ├── Toc.vue │ │ │ │ ├── Cover.vue │ │ │ │ ├── SafetyConsiderations.vue │ │ │ │ └── ActivityList.vue │ │ │ └── TocEntryPageNumber.vue │ │ └── TocSectionStartMarker.vue │ └── index.js ├── public │ └── favicon.ico ├── docker-setup.sh ├── babel.config.js ├── eslint-local-rules │ └── index.js ├── dist │ ├── prepareInMainThread.js.dist │ └── pdf.js.dist └── .gitignore ├── print ├── common ├── store │ ├── index.js │ └── README.md ├── locales │ ├── rm.json │ ├── de-CH-scout.json │ ├── en-CH-scout.json │ ├── fr-CH-scout.json │ ├── it-CH-scout.json │ ├── rm-CH-scout.json │ ├── en.json │ ├── fr.json │ ├── de.json │ └── it.json ├── .prettierignore ├── tsconfig.json ├── public │ ├── favicon.ico │ ├── fonts │ │ └── inter │ │ │ ├── InterDisplay-Black.otf │ │ │ ├── InterDisplay-Bold.otf │ │ │ ├── InterDisplay-Light.otf │ │ │ ├── InterDisplay-Thin.otf │ │ │ ├── InterDisplay-Italic.otf │ │ │ ├── InterDisplay-Medium.otf │ │ │ ├── InterDisplay-Regular.otf │ │ │ ├── InterDisplay-SemiBold.otf │ │ │ ├── InterDisplay-BoldItalic.otf │ │ │ ├── InterDisplay-ExtraBold.otf │ │ │ ├── InterDisplay-ExtraLight.otf │ │ │ ├── InterDisplay-ThinItalic.otf │ │ │ ├── InterDisplay-BlackItalic.otf │ │ │ ├── InterDisplay-LightItalic.otf │ │ │ ├── InterDisplay-MediumItalic.otf │ │ │ ├── InterDisplay-ExtraBoldItalic.otf │ │ │ ├── InterDisplay-SemiBoldItalic.otf │ │ │ └── InterDisplay-ExtraLightItalic.otf │ └── README.md ├── env.d.ts ├── layouts │ ├── health.vue │ └── README.md ├── .vscode │ └── settings.json ├── docker-setup.sh ├── server │ └── api │ │ └── health.js ├── components │ ├── README.md │ ├── scheduleEntry │ │ └── contentNode │ │ │ ├── NotImplemented.vue │ │ │ └── ColumnLayout.vue │ ├── generic │ │ ├── ErrorMessage.vue │ │ └── YSLogo.vue │ └── Toc │ │ ├── TocToc.vue │ │ └── TocCover.vue ├── pages │ ├── health │ │ └── index.vue │ └── README.md ├── assets │ ├── tailwind.css │ ├── README.md │ └── typography.css ├── .editorconfig ├── jsconfig.json ├── test │ └── package-lock.spec.js ├── eslint-local-rules │ └── index.js ├── plugins │ ├── README.md │ ├── hydrator.js │ └── dayjs.js ├── print.env ├── mixins │ └── dateHelperUTCFormatted.js ├── README.md └── vitest.config.ts ├── common ├── locales │ ├── en-CH-scout.json │ ├── it-CH-scout.json │ ├── fr-CH-scout.json │ ├── rm-CH-scout.json │ ├── rm.json │ └── de-CH-scout.json ├── helpers │ ├── dateFormat.js │ ├── userDisplayName.js │ ├── userLegalName.js │ ├── materialListsSorted.js │ ├── userInitials.js │ ├── campCollaborationLegalName.js │ ├── __tests__ │ │ ├── userDisplayName.spec.js │ │ ├── userInitials.spec.js │ │ └── userLegalName.spec.js │ ├── activityResponsibles.js │ ├── initials.js │ └── dayjs │ │ └── __tests__ │ │ └── formatDatePeriod.spec.js ├── assets │ └── logos │ │ ├── GSLogo.svg │ │ └── JSLogo.svg └── eslint-local-rules │ ├── packageDirectory.js │ └── __tests__ │ └── packageDirectory.spec.js ├── frontend ├── src │ ├── common │ ├── pdf │ ├── assets │ │ ├── fonts │ │ ├── logo.png │ │ ├── 140801151550_LOM.jpg │ │ ├── 080720_lotos_7896.jpg │ │ ├── 080720_lotos_7896_small.jpg │ │ ├── 140801151550_LOM_small.jpg │ │ ├── icons │ │ │ ├── ColumnLayout.svg │ │ │ ├── ResponsiveLayout.svg │ │ │ ├── PaperSize.svg │ │ │ └── BigScreen.svg │ │ └── CeviLogo.svg │ ├── plugins │ │ ├── color.js │ │ ├── slugify.js │ │ ├── dayjs.js │ │ ├── veeValidate │ │ │ ├── oneEmojiOrTwoCharacters.js │ │ │ ├── greaterThan.js │ │ │ ├── lessThanOrEqual_date.js │ │ │ └── greaterThanOrEqual_date.js │ │ └── index.js │ ├── locales │ │ ├── en-CH-scout.json │ │ ├── it-CH-scout.json │ │ ├── rm-CH-scout.json │ │ ├── de-CH-scout.json │ │ └── fr-CH-scout.json │ ├── components │ │ ├── layout │ │ │ ├── IconSpacer.vue │ │ │ ├── ContentActions.vue │ │ │ └── TextAlignBaseline.vue │ │ ├── buttons │ │ │ ├── ButtonCancel.vue │ │ │ ├── ButtonContinue.vue │ │ │ ├── ButtonRetry.vue │ │ │ └── ButtonBack.vue │ │ ├── dashboard │ │ │ ├── FilterDivider.vue │ │ │ └── BooleanFilter.vue │ │ ├── print │ │ │ ├── config │ │ │ │ ├── TocConfig.vue │ │ │ │ └── CoverConfig.vue │ │ │ └── print-nuxt │ │ │ │ └── DownloadNuxtPdfButton.vue │ │ ├── form │ │ │ ├── base │ │ │ │ └── EForm.vue │ │ │ ├── tiptap │ │ │ │ └── TiptapToolbarButton.vue │ │ │ ├── api │ │ │ │ └── ApiForm.vue │ │ │ └── ServerError.vue │ │ ├── collaborator │ │ │ └── isOwnCampCollaboration.js │ │ ├── campAdmin │ │ │ ├── DialogMaterialListForm.vue │ │ │ └── DialogActivityProgressLabelForm.vue │ │ ├── activity │ │ │ └── content │ │ │ │ ├── layout │ │ │ │ └── LayoutItem.vue │ │ │ │ └── contentTypeIcons.js │ │ ├── program │ │ │ └── picasso │ │ │ │ └── dateHelperVCalendar.js │ │ ├── material │ │ │ └── shortScheduleEntryDescription.js │ │ ├── toast │ │ │ └── toasts.js │ │ ├── generic │ │ │ └── GenericPage.vue │ │ └── navigation │ │ │ └── Logo.vue │ ├── mixins │ │ └── contentNodeMixin.js │ ├── views │ │ ├── admin │ │ │ ├── Checklist.vue │ │ │ └── Checklists.vue │ │ ├── camp │ │ │ ├── checklist │ │ │ │ └── Checklist.vue │ │ │ ├── material │ │ │ │ └── SideBarMaterialLists.vue │ │ │ └── admin │ │ │ │ └── Checklists.vue │ │ ├── CampCreate.vue │ │ └── auth │ │ │ └── LoginCallback.vue │ └── test │ │ └── util.js ├── public │ ├── favicon.ico │ ├── browserassets │ │ ├── logo@192px.png │ │ ├── logo@512px.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── apple-touch-icon.png │ │ └── mstile-150x150.png │ ├── environment.js │ ├── browserconfig.xml │ └── favicon.svg ├── tests │ ├── globalSetup.js │ ├── infrastructure │ │ └── package-lock.spec.js │ └── setup.js ├── .prettierignore ├── jsconfig.json ├── .editorconfig ├── babel.config.js ├── .vscode │ └── settings.json ├── eslint-local-rules │ └── index.js ├── README.md ├── .gitignore ├── vue.config.js └── docker-setup.sh ├── .helm ├── .gitignore ├── ecamp3 │ ├── files │ │ ├── vcl │ │ ├── db-backup-restore-image │ │ │ ├── Dockerfile │ │ │ └── docker-compose.yml │ │ ├── db_backup_job │ │ │ ├── .env-example │ │ │ ├── docker-compose.yml │ │ │ └── README.md │ │ └── hook_db_restore │ │ │ ├── .env-example │ │ │ ├── docker-compose.yml │ │ │ └── update-support-email.sh │ ├── .gitignore │ ├── helmfile.yaml │ ├── README.md │ ├── templates │ │ ├── serviceaccount.yaml │ │ ├── print_browserless_secrets.yaml │ │ ├── browserless_configmap.yaml │ │ ├── print_service.yaml │ │ ├── tests │ │ │ └── test-connection.yaml │ │ ├── frontend_service.yaml │ │ ├── browserless_service.yaml │ │ ├── api_service.yaml │ │ ├── api_cache_vcl_configmap.yaml │ │ └── basic_auth_secret.yml │ └── .helmignore ├── build-and-deploy.sh └── deploy-to-cluster.sh ├── .ops ├── ingress │ ├── .gitignore │ ├── .helmignore │ ├── Chart.lock │ └── deploy.sh ├── performance-test │ ├── measurements │ │ └── .gitkeep │ ├── .env.example │ ├── .env.example.yaml │ ├── .gitignore │ ├── docker-compose.yml │ └── package.json ├── aws-setup │ ├── .prettierignore │ ├── .gitignore │ ├── Pulumi.yaml │ ├── Pulumi.dev.yaml │ ├── Pulumi.prod.yaml │ ├── Pulumi.staging.yaml │ └── tsconfig.json ├── ops-dashboard │ ├── .helmignore │ ├── .gitignore │ ├── templates │ │ ├── kubernetes_dashboard_cluster_admin_user.yaml │ │ └── kubernetes_dashboard_cluster_admin_cluster_role_binding.yaml │ ├── .env-example │ ├── helmfile.yaml │ ├── env.example.yaml │ └── Chart.lock ├── ecamp3-logging │ ├── .gitignore │ ├── .helmignore │ ├── files │ │ ├── elasticsearch │ │ │ └── remove-old-indexes │ │ │ │ ├── .env-example │ │ │ │ └── docker-compose.yml │ │ └── kibana │ │ │ ├── restore-kibana-objects.sh │ │ │ └── dump-kibana-objects.sh │ ├── Chart.lock │ ├── helmfile.yaml │ └── templates │ │ ├── kibana │ │ └── kibana_service.yaml │ │ ├── elasticsearch │ │ ├── elasticsearch_service.yaml │ │ └── remove_old_indexes_configmap.yaml │ │ └── _helpers.tpl └── observability │ └── README.md ├── translation └── .gitignore ├── .env.ci ├── .gitattributes ├── .gitignore ├── e2e ├── .editorconfig ├── specs │ └── httpCache │ │ ├── camps.cy.js │ │ ├── responses │ │ └── content_types_entity.json │ │ └── root.cy.js ├── .gitignore └── tasks │ └── getPdfProperties.js ├── .prettierrc ├── create-ecamp3-test-database.sh ├── .docker-hub ├── frontend │ └── docker-entrypoint.d │ │ └── 50-add-version-to-environment-js-url.sh └── varnish │ └── Dockerfile ├── .dockerignore ├── pgadmin-servers.json ├── .vscode └── settings.json ├── .github ├── actions │ └── setup-helmfile │ │ └── action.yaml └── workflows │ └── pull-request-rules.yml ├── crowdin.yml └── wait-for-container-startup.sh /.nvmrc: -------------------------------------------------------------------------------- 1 | 24.12.0 2 | -------------------------------------------------------------------------------- /.cache/npm/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /api/config/jwt/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /api/fixtures/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pdf/common: -------------------------------------------------------------------------------- 1 | ../common/ -------------------------------------------------------------------------------- /print/common: -------------------------------------------------------------------------------- 1 | ../common -------------------------------------------------------------------------------- /print/store/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.cache/composer/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /api/migrations/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /print/locales/rm.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /.cache/npm/sentry-cli/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /api/src/Controller/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /api/src/Repository/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /common/locales/en-CH-scout.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /common/locales/it-CH-scout.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /frontend/src/common: -------------------------------------------------------------------------------- 1 | ../../common -------------------------------------------------------------------------------- /frontend/src/pdf: -------------------------------------------------------------------------------- 1 | ../../pdf/dist -------------------------------------------------------------------------------- /.helm/.gitignore: -------------------------------------------------------------------------------- 1 | /*.pem 2 | .env 3 | -------------------------------------------------------------------------------- /.ops/ingress/.gitignore: -------------------------------------------------------------------------------- 1 | /charts 2 | -------------------------------------------------------------------------------- /api/migrations/empty-data/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /print/locales/de-CH-scout.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /print/locales/en-CH-scout.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /print/locales/fr-CH-scout.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /print/locales/it-CH-scout.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /print/locales/rm-CH-scout.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /translation/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.env.ci: -------------------------------------------------------------------------------- 1 | USER_ID=1001 2 | XDEBUG_MODE=off -------------------------------------------------------------------------------- /.ops/ingress/.helmignore: -------------------------------------------------------------------------------- 1 | /deploy.sh 2 | -------------------------------------------------------------------------------- /.ops/performance-test/measurements/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /print/.prettierignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | locales/ 3 | -------------------------------------------------------------------------------- /.helm/ecamp3/files/vcl: -------------------------------------------------------------------------------- 1 | ../../../api/docker/varnish/vcl -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | Dockerfile eol=lf 2 | *.sh eol=lf -------------------------------------------------------------------------------- /frontend/src/assets/fonts: -------------------------------------------------------------------------------- 1 | ../../../pdf/src/assets/fonts/ -------------------------------------------------------------------------------- /.helm/ecamp3/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | /env.yaml 3 | /values.yaml 4 | -------------------------------------------------------------------------------- /pdf/src/renderer/styleStore.js: -------------------------------------------------------------------------------- 1 | export const styleStore = {} 2 | -------------------------------------------------------------------------------- /.ops/aws-setup/.prettierignore: -------------------------------------------------------------------------------- 1 | /.aws 2 | /.pulumi 3 | /package*.json 4 | -------------------------------------------------------------------------------- /.ops/ops-dashboard/.helmignore: -------------------------------------------------------------------------------- 1 | /deploy.sh 2 | /values.access.yaml 3 | -------------------------------------------------------------------------------- /print/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.nuxt/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /.ops/aws-setup/.gitignore: -------------------------------------------------------------------------------- 1 | /.aws 2 | /.pulumi 3 | /bin/ 4 | /node_modules/ 5 | -------------------------------------------------------------------------------- /.ops/performance-test/.env.example: -------------------------------------------------------------------------------- 1 | #API_ROOT_URL=https://dev.ecamp3.ch/ 2 | -------------------------------------------------------------------------------- /.ops/ecamp3-logging/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | /env.yaml 3 | /charts 4 | /values.yaml 5 | -------------------------------------------------------------------------------- /api/translations/validators.rm.yml: -------------------------------------------------------------------------------- 1 | This is a test message for i18n variants: "rm" 2 | -------------------------------------------------------------------------------- /api/config/packages/test/mailer.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | mailer: 3 | dsn: 'null://null' 4 | -------------------------------------------------------------------------------- /api/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecamp/ecamp3/HEAD/api/public/favicon.ico -------------------------------------------------------------------------------- /api/translations/validators.de_CH.yml: -------------------------------------------------------------------------------- 1 | This is a test message for i18n variants: "de_CH" 2 | -------------------------------------------------------------------------------- /pdf/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecamp/ecamp3/HEAD/pdf/public/favicon.ico -------------------------------------------------------------------------------- /api/config/packages/dev/mailer.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | mailer: 3 | dsn: '%env(MAILER_DSN)%' 4 | -------------------------------------------------------------------------------- /api/config/packages/prod/mailer.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | mailer: 3 | dsn: '%env(MAILER_DSN)%' 4 | -------------------------------------------------------------------------------- /api/config/packages/test/hautelook_alice.yaml: -------------------------------------------------------------------------------- 1 | hautelook_alice: 2 | fixtures_path: fixtures 3 | -------------------------------------------------------------------------------- /print/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecamp/ecamp3/HEAD/print/public/favicon.ico -------------------------------------------------------------------------------- /.ops/ops-dashboard/.gitignore: -------------------------------------------------------------------------------- 1 | /.env 2 | /charts 3 | /env.yaml 4 | /values.yaml 5 | /values.out.yaml 6 | -------------------------------------------------------------------------------- /.ops/performance-test/.env.example.yaml: -------------------------------------------------------------------------------- 1 | # Example: 2 | # API_ROOT_URL: "https://dev.ecamp3.ch/" 3 | -------------------------------------------------------------------------------- /api/config/routes/api_platform.yaml: -------------------------------------------------------------------------------- 1 | api_platform: 2 | resource: . 3 | type: api_platform 4 | -------------------------------------------------------------------------------- /api/docker/varnish/vcl/_config.vcl: -------------------------------------------------------------------------------- 1 | backend default { 2 | .host = "api"; 3 | .port = "3001"; 4 | } -------------------------------------------------------------------------------- /api/translations/validators.de_CH_scout.yml: -------------------------------------------------------------------------------- 1 | This is a test message for i18n variants: "de_CH_scout" 2 | -------------------------------------------------------------------------------- /api/translations/validators.en_CH_scout.yml: -------------------------------------------------------------------------------- 1 | This is a test message for i18n variants: "en_CH_scout" 2 | -------------------------------------------------------------------------------- /api/translations/validators.fr_CH_scout.yml: -------------------------------------------------------------------------------- 1 | This is a test message for i18n variants: "fr_CH_scout" 2 | -------------------------------------------------------------------------------- /api/translations/validators.it_CH_scout.yml: -------------------------------------------------------------------------------- 1 | This is a test message for i18n variants: "it_CH_scout" 2 | -------------------------------------------------------------------------------- /api/translations/validators.rm_CH_scout.yml: -------------------------------------------------------------------------------- 1 | This is a test message for i18n variants: "rm_CH_scout" 2 | -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecamp/ecamp3/HEAD/frontend/public/favicon.ico -------------------------------------------------------------------------------- /.ops/ecamp3-logging/.helmignore: -------------------------------------------------------------------------------- 1 | .env 2 | /deploy.sh 3 | /values.yaml 4 | /values.yaml.gotmpl 5 | /env.yaml -------------------------------------------------------------------------------- /.ops/performance-test/.gitignore: -------------------------------------------------------------------------------- 1 | /measurements 2 | !/measurements/.gitkeep 3 | /node_modules 4 | .env 5 | -------------------------------------------------------------------------------- /api/config/packages/dev/routing.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | router: 3 | strict_requirements: true 4 | -------------------------------------------------------------------------------- /api/config/packages/prod/api_platform.yaml: -------------------------------------------------------------------------------- 1 | api_platform: 2 | graphql: 3 | enabled: false 4 | -------------------------------------------------------------------------------- /api/config/packages/test/doctrine_migrations.yaml: -------------------------------------------------------------------------------- 1 | parameters: 2 | data_migrations_dir: empty-data 3 | -------------------------------------------------------------------------------- /api/config/packages/test/nelmio_alice.yaml: -------------------------------------------------------------------------------- 1 | imports: 2 | - { resource: ../dev/nelmio_alice.yaml } 3 | -------------------------------------------------------------------------------- /api/config/packages/test/routing.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | router: 3 | strict_requirements: true 4 | -------------------------------------------------------------------------------- /api/phpstan.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 5 3 | paths: 4 | - src 5 | treatPhpDocTypesAsCertain: false 6 | -------------------------------------------------------------------------------- /frontend/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecamp/ecamp3/HEAD/frontend/src/assets/logo.png -------------------------------------------------------------------------------- /frontend/tests/globalSetup.js: -------------------------------------------------------------------------------- 1 | export function setup() { 2 | process.env.TZ = 'Pacific/Tongatapu' 3 | } 4 | -------------------------------------------------------------------------------- /.ops/aws-setup/Pulumi.yaml: -------------------------------------------------------------------------------- 1 | name: ecamp-core 2 | runtime: nodejs 3 | description: The aws setup for eCamp v3 4 | -------------------------------------------------------------------------------- /api/config/packages/test/validator.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | validation: 3 | not_compromised_password: false 4 | -------------------------------------------------------------------------------- /api/docker/php/conf.d/api-platform.prod.ini: -------------------------------------------------------------------------------- 1 | opcache.preload_user=root 2 | opcache.preload=/app/config/preload.php 3 | -------------------------------------------------------------------------------- /frontend/.prettierignore: -------------------------------------------------------------------------------- 1 | src/common/locales/ 2 | src/locales/ 3 | /data 4 | /dist 5 | .vscode 6 | /public/twemoji 7 | -------------------------------------------------------------------------------- /common/locales/fr-CH-scout.json: -------------------------------------------------------------------------------- 1 | { 2 | "print": { 3 | "story": { 4 | "title": "Fil rouge" 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /frontend/src/assets/140801151550_LOM.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecamp/ecamp3/HEAD/frontend/src/assets/140801151550_LOM.jpg -------------------------------------------------------------------------------- /common/locales/rm-CH-scout.json: -------------------------------------------------------------------------------- 1 | { 2 | "print": { 3 | "story": { 4 | "title": "Fil cotschen" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /frontend/src/assets/080720_lotos_7896.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ecamp/ecamp3/HEAD/frontend/src/assets/080720_lotos_7896.jpg -------------------------------------------------------------------------------- /.ops/ecamp3-logging/files/elasticsearch/remove-old-indexes/.env-example: -------------------------------------------------------------------------------- 1 | ELASTICSEARCH_URL=http://localhost:9200 2 | MAX_INDEX_AGE=15 3 | -------------------------------------------------------------------------------- /api/.coveralls.yml: -------------------------------------------------------------------------------- 1 | coverage_clover: build/logs/clover.xml 2 | json_path: build/logs/coveralls-upload.json 3 | service_name: github 4 | -------------------------------------------------------------------------------- /api/src/Entity/SupportsContentNodeChildren.php: -------------------------------------------------------------------------------- 1 | { 5 | ColorSpace.register(sRGB) 6 | }, 7 | } 8 | -------------------------------------------------------------------------------- /.ops/aws-setup/Pulumi.dev.yaml: -------------------------------------------------------------------------------- 1 | encryptionsalt: v1:CdKPMfceMA4=:v1:rlPnkGuNOMP44Lvd:E0r294YKkNTLweaqLUICMda0uPHKEg== 2 | config: 3 | aws:region: eu-west-3 4 | ecamp-core:env: dev 5 | -------------------------------------------------------------------------------- /.ops/aws-setup/Pulumi.prod.yaml: -------------------------------------------------------------------------------- 1 | encryptionsalt: v1:fMldUZIpLOs=:v1:0Vd6ZXTXZIlciRYQ:IlSxNR4210bawhbGLeYUFdT3LJL8Fg== 2 | config: 3 | aws:region: eu-west-3 4 | ecamp-core:env: prod 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "singleQuote": true, 4 | "semi": false, 5 | "bracketSameLine": false, 6 | "bracketSpacing": true, 7 | "printWidth": 90 8 | } 9 | -------------------------------------------------------------------------------- /frontend/src/plugins/slugify.js: -------------------------------------------------------------------------------- 1 | import slugify from 'slugify' 2 | 3 | slugify.extend({ 4 | '@': '(at)', 5 | '.': ' ', 6 | ':': ' ', 7 | }) 8 | 9 | export { slugify } 10 | -------------------------------------------------------------------------------- /pdf/docker-setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | npm ci --verbose 5 | 6 | if [ "$CI" = 'true' ] ; then 7 | npm run build 8 | else 9 | npm run watch 10 | fi 11 | -------------------------------------------------------------------------------- /.ops/aws-setup/Pulumi.staging.yaml: -------------------------------------------------------------------------------- 1 | encryptionsalt: v1:XBD0QUsfJx8=:v1:kE3gKM26lHSNXQql:hTPT6LNJt9u/qKKfo9PlrAYY/oX7Sw== 2 | config: 3 | aws:region: eu-west-3 4 | ecamp-core:env: staging 5 | -------------------------------------------------------------------------------- /api/config/packages/test/http_cache.yaml: -------------------------------------------------------------------------------- 1 | fos_http_cache: 2 | proxy_client: 3 | noop: ~ 4 | cache_manager: 5 | custom_proxy_client: fos_http_cache.proxy_client.noop 6 | -------------------------------------------------------------------------------- /api/src/Serializer/Normalizer/UnsupportedRelationException.php: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
5 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /api/src/Entity/HasParentInterface.php: -------------------------------------------------------------------------------- 1 |

' 7 | } 8 | -------------------------------------------------------------------------------- /frontend/babel.config.js: -------------------------------------------------------------------------------- 1 | // noinspection JSUnusedGlobalSymbols 2 | export const presets = ['@vue/app'] 3 | export const env = { 4 | test: { 5 | plugins: ['require-context-hook'], 6 | }, 7 | } 8 | -------------------------------------------------------------------------------- /frontend/src/assets/icons/ColumnLayout.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /print/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "javascript.format.enable": false, 3 | "eslint.format.enable": false, 4 | "i18n-ally.localesPaths": ["locales"], 5 | "i18n-ally.keystyle": "nested" 6 | } 7 | -------------------------------------------------------------------------------- /api/config/packages/translation.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | default_locale: en 3 | translator: 4 | default_path: '%kernel.project_dir%/translations' 5 | fallbacks: 6 | - en 7 | -------------------------------------------------------------------------------- /api/src/Entity/CopyFromPrototypeInterface.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /e2e/specs/httpCache/camps.cy.js: -------------------------------------------------------------------------------- 1 | it("doesn't cache /camps", () => { 2 | const uri = '/api/camps' 3 | Cypress.session.clearAllSavedSessions() 4 | cy.login('test@example.com') 5 | cy.expectCachePass(uri) 6 | }) 7 | -------------------------------------------------------------------------------- /api/config/preload.php: -------------------------------------------------------------------------------- 1 | pdf(CampPrint, props, onProgress) 5 | export { render, prepare } 6 | -------------------------------------------------------------------------------- /.helm/build-and-deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | SCRIPT_DIR=$(realpath "$(dirname "$0")") 6 | REPO_DIR=$(realpath "$SCRIPT_DIR"/..) 7 | 8 | . $"$SCRIPT_DIR"/build-images.sh 9 | . $"$SCRIPT_DIR"/deploy-to-cluster.sh 10 | -------------------------------------------------------------------------------- /frontend/src/locales/en-CH-scout.json: -------------------------------------------------------------------------------- 1 | { 2 | "entity": { 3 | "user": { 4 | "fields": { 5 | "nickname": "Scout Name" 6 | } 7 | } 8 | }, 9 | "global": { 10 | "language": "English (Scout)" 11 | } 12 | } -------------------------------------------------------------------------------- /print/server/api/health.js: -------------------------------------------------------------------------------- 1 | export default defineEventHandler(async (event) => { 2 | setResponseStatus(event, 200) 3 | 4 | return { 5 | uptime: process.uptime(), 6 | message: 'Ok', 7 | date: new Date(), 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /api/config/packages/dev/nelmio_alice.yaml: -------------------------------------------------------------------------------- 1 | nelmio_alice: 2 | functions_blacklist: 3 | - 'current' 4 | - 'shuffle' 5 | - 'date' 6 | - 'time' 7 | - 'file' 8 | - 'md5' 9 | - 'sha1' 10 | -------------------------------------------------------------------------------- /api/src/Entity/SortableEntityInterface.php: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /print/components/README.md: -------------------------------------------------------------------------------- 1 | # COMPONENTS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | The components directory contains your Vue.js Components. 6 | 7 | _Nuxt.js doesn't supercharge these components._ 8 | -------------------------------------------------------------------------------- /api/public/index.php: -------------------------------------------------------------------------------- 1 | 2 |

Ok

3 | 4 | 5 | 16 | -------------------------------------------------------------------------------- /.helm/ecamp3/files/db-backup-restore-image/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:12.12-slim 2 | 3 | ENV DEBIAN_FRONTEND="noninteractive" 4 | RUN apt-get update && \ 5 | apt-get install -y \ 6 | awscli=2.9.19-1 \ 7 | gpg \ 8 | postgresql-client-15 9 | -------------------------------------------------------------------------------- /print/locales/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "global": { 3 | "margin": { 4 | "pageCounter": { 5 | "of": "von", 6 | "page": "Seite" 7 | } 8 | }, 9 | "page": { 10 | "counter": "Seite ${index} von ${total}" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /print/locales/it.json: -------------------------------------------------------------------------------- 1 | { 2 | "global": { 3 | "margin": { 4 | "pageCounter": { 5 | "of": "di", 6 | "page": "Pagina" 7 | } 8 | }, 9 | "page": { 10 | "counter": "Pagina ${indice} di ${totale}" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.docker-hub/varnish/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG VERSION=8.0.0 2 | 3 | FROM varnish:${VERSION} 4 | 5 | USER root 6 | 7 | RUN set -e; \ 8 | apt-get update; \ 9 | apt-get -y install prometheus-varnish-exporter; 10 | 11 | RUN rm -rf /var/lib/apt/lists/*; 12 | 13 | USER varnish -------------------------------------------------------------------------------- /.ops/ingress/Chart.lock: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: ingress-nginx 3 | repository: https://kubernetes.github.io/ingress-nginx 4 | version: 4.14.1 5 | digest: sha256:1da613ab45c588a2919dd2027d982f1dbea0ef60252c9e39b9fd929bcda1ede6 6 | generated: "2025-12-12T15:16:15.379936173Z" 7 | -------------------------------------------------------------------------------- /api/config/packages/validator.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | validation: 3 | # Enables validator auto-mapping support. 4 | # For instance, basic validation constraints will be inferred from Doctrine's metadata. 5 | auto_mapping: 6 | App\Entity\: [] 7 | -------------------------------------------------------------------------------- /api/config/routes.yaml: -------------------------------------------------------------------------------- 1 | #index: 2 | # path: / 3 | # controller: App\Controller\DefaultController::index 4 | authentication_token: 5 | path: /authentication_token 6 | methods: ['POST'] 7 | api_refresh_token: 8 | path: /token/refresh 9 | methods: ['POST'] 10 | -------------------------------------------------------------------------------- /print/assets/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | /* 6 | * TODO: Remove once https://github.com/tailwindlabs/tailwindcss/pull/12128 is merged 7 | */ 8 | .tw-break-anywhere { 9 | overflow-wrap: anywhere; 10 | } 11 | -------------------------------------------------------------------------------- /.helm/ecamp3/files/db-backup-restore-image/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | db-backup-restore-image: 3 | image: ${CONTAINER_REGISTRY:-docker.io}/${REPO_OWNER:-ecamp}/ecamp3-db-backup-restore:${VERSION:-local} 4 | build: 5 | context: . 6 | dockerfile: Dockerfile 7 | -------------------------------------------------------------------------------- /.ops/ecamp3-logging/Chart.lock: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: fluent-operator 3 | repository: https://fluent.github.io/helm-charts 4 | version: 3.5.0 5 | digest: sha256:988588f732cf8645a1eb380c66e4683807f49aa08648437c0fd2e2d454db9817 6 | generated: "2025-11-01T00:12:16.626020606Z" 7 | -------------------------------------------------------------------------------- /api/config/packages/dev/debug.yaml: -------------------------------------------------------------------------------- 1 | debug: 2 | # Forwards VarDumper Data clones to a centralized server allowing to inspect dumps on CLI or in your browser. 3 | # See the "server:dump" command to start a new server. 4 | dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%" 5 | -------------------------------------------------------------------------------- /api/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "php-cs-fixer.executablePath": "${workspaceFolder}/vendor/bin/php-cs-fixer", 3 | "php-cs-fixer.config": "./.php-cs-fixer.php", 4 | "phpunit.files": "tests/**/*Test.php", 5 | "phpunit.args": [ 6 | "-cphpunit.nodocker.xml" 7 | ], 8 | } -------------------------------------------------------------------------------- /api/config/routes/dev/web_profiler.yaml: -------------------------------------------------------------------------------- 1 | web_profiler_wdt: 2 | resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml' 3 | prefix: /_wdt 4 | 5 | web_profiler_profiler: 6 | resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml' 7 | prefix: /_profiler 8 | -------------------------------------------------------------------------------- /api/src/Validator/AssertNoLoop.php: -------------------------------------------------------------------------------- 1 | { 5 | test('uses lockfileVersion 3', () => { 6 | expect(lockfileVersion).toBe(3) 7 | }) 8 | }) 9 | -------------------------------------------------------------------------------- /frontend/src/components/buttons/ButtonCancel.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /frontend/src/components/buttons/ButtonContinue.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /print/components/scheduleEntry/contentNode/NotImplemented.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | -------------------------------------------------------------------------------- /print/layouts/README.md: -------------------------------------------------------------------------------- 1 | # LAYOUTS 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your Application Layouts. 6 | 7 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/views#layouts). 8 | -------------------------------------------------------------------------------- /api/src/Util/DateTimeUtil.php: -------------------------------------------------------------------------------- 1 | getTimestamp() - $from->getTimestamp()) / 60)); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /api/src/Validator/ContentNode/AssertNoRootChange.php: -------------------------------------------------------------------------------- 1 | { 5 | test('uses lockfileVersion 3', () => { 6 | expect(lockfileVersion).toBe(3) 7 | }) 8 | }) 9 | -------------------------------------------------------------------------------- /.ops/ecamp3-logging/files/elasticsearch/remove-old-indexes/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | remove-old-indexes: 3 | image: node:24.11.1 4 | volumes: 5 | - ./src:/src 6 | command: 7 | - node 8 | - /src/remove-old-indexes.mjs 9 | env_file: .env 10 | network_mode: host 11 | -------------------------------------------------------------------------------- /.ops/ecamp3-logging/helmfile.yaml: -------------------------------------------------------------------------------- 1 | environments: 2 | default: 3 | values: 4 | - ./env.yaml 5 | --- 6 | repositories: 7 | - name: fluent 8 | url: https://fluent.github.io/helm-charts 9 | 10 | releases: 11 | - name: "" 12 | chart: . 13 | values: 14 | - ./values.yaml.gotmpl 15 | -------------------------------------------------------------------------------- /api/src/Entity/RefreshToken.php: -------------------------------------------------------------------------------- 1 | 2 | | 3 | 4 | 5 | 10 | 11 | 17 | -------------------------------------------------------------------------------- /frontend/src/components/layout/ContentActions.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | -------------------------------------------------------------------------------- /.helm/ecamp3/README.md: -------------------------------------------------------------------------------- 1 | # Deploying to a Kubernetes Cluster 2 | 3 | eCamp v3 comes with a native integration with [Kubernetes](https://kubernetes.io/) and the [Helm](https://helm.sh/) 4 | package manager. 5 | 6 | [Learn how to deploy in the API platform documentation](https://api-platform.com/docs/deployment/kubernetes/). 7 | -------------------------------------------------------------------------------- /api/templates/emails/passwordResetLink.en.text.twig: -------------------------------------------------------------------------------- 1 | Password reset 2 | 3 | Hi {{ name | raw }}, 4 | 5 | We have received a request to reset your password on eCamp. 6 | 7 | If that was initiated by you, please click below link to set a new password: 8 | {{ url | raw }} 9 | 10 | Cheers, 11 | your eCamp team 12 | -------------------------------------------------------------------------------- /api/tests/State/Util/MockableClosure.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #263238 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /api/src/Validator/ChecklistItem/AssertBelongsToSameCamp.php: -------------------------------------------------------------------------------- 1 | 7 | (list.campCollaboration == null ? 'NonUserList_' : 'UserList_') + 8 | list.name.toLowerCase() 9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /print/pages/README.md: -------------------------------------------------------------------------------- 1 | # PAGES 2 | 3 | This directory contains your Application Views and Routes. 4 | The framework reads all the `*.vue` files inside this directory and creates the router of your application. 5 | 6 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/routing). 7 | -------------------------------------------------------------------------------- /frontend/src/assets/icons/PaperSize.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /frontend/src/components/buttons/ButtonRetry.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /frontend/src/plugins/dayjs.js: -------------------------------------------------------------------------------- 1 | import dayjs from '@/common/helpers/dayjs.js' 2 | 3 | export default { 4 | install: (Vue) => { 5 | Object.defineProperties(Vue.prototype, { 6 | $date: { 7 | get() { 8 | return dayjs 9 | }, 10 | }, 11 | }) 12 | Vue.dayjs = dayjs 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /api/config/packages/prod/deprecations.yaml: -------------------------------------------------------------------------------- 1 | # As of Symfony 5.1, deprecations are logged in the dedicated "deprecation" channel when it exists 2 | #monolog: 3 | # channels: [deprecation] 4 | # handlers: 5 | # deprecation: 6 | # type: stream 7 | # channels: [deprecation] 8 | # path: php://stderr 9 | -------------------------------------------------------------------------------- /api/src/Validator/ChecklistItem/AssertBelongsToSameChecklist.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hello world! 6 | 7 | 8 | 9 | 10 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.helm/ecamp3/files/db_backup_job/.env-example: -------------------------------------------------------------------------------- 1 | APP_NAME=test-db-backup-job 2 | DATABASE_URL= 3 | #if you want to backup your local database: 4 | #DATABASE_URL=postgresql://ecamp3:ecamp3@:5432/ecamp3dev 5 | ENCRYPTION_KEY=test 6 | S3_ENDPOINT=https://s3.eu-west-3.amazonaws.com 7 | S3_BUCKET= 8 | S3_ACCESS_KEY_ID= 9 | S3_ACCESS_KEY= 10 | -------------------------------------------------------------------------------- /api/src/HttpCache/CanGenerateTagsInterface.php: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 19 | -------------------------------------------------------------------------------- /e2e/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /data 4 | /dist 5 | 6 | 7 | /reports/ 8 | selenium-debug.log 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | 15 | # Editor directories and files 16 | .idea 17 | .vscode 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw* 23 | 24 | # yalc 25 | .yalc 26 | yalc.lock 27 | -------------------------------------------------------------------------------- /frontend/src/components/print/config/CoverConfig.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 19 | -------------------------------------------------------------------------------- /api/templates/emails/campCollaborationInvite.en.text.twig: -------------------------------------------------------------------------------- 1 | Invitation to camp "{{ camp_title | raw }}" 2 | 3 | You have been invited by {{ by_user | raw }} to collaborate in the following camp: 4 | 5 | Title: {{ camp_title | raw }} 6 | Organizer: {{ camp_organizer | raw }} 7 | 8 | Answer the invitation: 9 | {{ url | raw }} 10 | 11 | Cheers, 12 | your eCamp team 13 | -------------------------------------------------------------------------------- /pdf/dist/prepareInMainThread.js.dist: -------------------------------------------------------------------------------- 1 | // This file will be replaced with generated code by the pdf build service. 2 | 3 | async function prepareInMainThread(config) { 4 | throw new Error('Clientside PDF generation code is not ready yet. Please ensure that @ecamp3/client-pdf has been built without any compiler errors.'); 5 | } 6 | export { 7 | prepareInMainThread 8 | }; 9 | -------------------------------------------------------------------------------- /frontend/src/components/form/base/EForm.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | -------------------------------------------------------------------------------- /frontend/src/plugins/veeValidate/oneEmojiOrTwoCharacters.js: -------------------------------------------------------------------------------- 1 | import { size } from 'lodash-es' 2 | 3 | export default (i18n) => ({ 4 | validate: (value) => { 5 | return /\p{Extended_Pictographic}/u.test(value) ? size(value) <= 1 : value.length <= 2 6 | }, 7 | message: (field, values) => 8 | i18n.tc('global.validation.oneEmojiOrTwoCharacters', 0, values), 9 | }) 10 | -------------------------------------------------------------------------------- /pdf/dist/pdf.js.dist: -------------------------------------------------------------------------------- 1 | // This file will be replaced with generated code by the pdf build service. 2 | 3 | const prepare = false; 4 | const render = (props = {}) => { 5 | throw new Error('Clientside PDF generation code is not ready yet. Please ensure that @ecamp3/client-pdf has been built without any compiler errors.'); 6 | }; 7 | export { 8 | prepare, 9 | render 10 | }; 11 | -------------------------------------------------------------------------------- /.ops/performance-test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "performance-test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "script.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "@types/k6": "1.4.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /api/src/Entity/Languages.php: -------------------------------------------------------------------------------- 1 | ((time[0] - 1) % 24) + 1) 13 | } 14 | -------------------------------------------------------------------------------- /e2e/specs/httpCache/responses/content_types_entity.json: -------------------------------------------------------------------------------- 1 | { 2 | "_links": { 3 | "self": { 4 | "href": "/api/content_types/318e064ea0c9" 5 | }, 6 | "contentNodes": { 7 | "href": "/api/content_node/single_texts?contentType=%2Fapi%2Fcontent_types%2F318e064ea0c9" 8 | } 9 | }, 10 | "name": "Storycontext", 11 | "active": true, 12 | "id": "318e064ea0c9" 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/assets/icons/BigScreen.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /.ops/ops-dashboard/.env-example: -------------------------------------------------------------------------------- 1 | COOKIE_SECRET= 2 | 3 | GRAFANA_PROXY_HOST= 4 | GRAFANA_PROXY_OAUTH_CLIENT_ID= 5 | GRAFANA_PROXY_OAUTH_CLIENT_SECRET= 6 | 7 | KUBERNETES_DASHBOARD_PROXY_HOST= 8 | KUBERNETES_DASHBOARD_PROXY_OAUTH_CLIENT_ID= 9 | KUBERNETES_DASHBOARD_PROXY_OAUTH_CLIENT_SECRET= 10 | 11 | LOGGING_PROXY_HOST= 12 | LOGGING_PROXY_OAUTH_CLIENT_ID= 13 | LOGGING_PROXY_OAUTH_CLIENT_SECRET= 14 | -------------------------------------------------------------------------------- /api/src/InputFilter/InvalidOptionsException.php: -------------------------------------------------------------------------------- 1 | options; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/components/form/tiptap/TiptapToolbarButton.vue: -------------------------------------------------------------------------------- 1 | 6 | 14 | -------------------------------------------------------------------------------- /api/src/Validator/Period/AssertGreaterThanOrEqualToLastScheduleEntryEnd.php: -------------------------------------------------------------------------------- 1 | { 4 | definePayloadReducer('JSONifiable', (data) => { 5 | if (data && typeof data === 'object' && 'toJSON' in data) { 6 | return JSON.stringify(data.toJSON()) 7 | } 8 | }) 9 | definePayloadReviver('JSONifiable', (data) => JSON.parse(data)) 10 | }) 11 | -------------------------------------------------------------------------------- /api/config/packages/routing.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | router: 3 | utf8: true 4 | 5 | # Configure how to generate URLs in non-HTTP contexts, such as CLI commands. 6 | # See https://symfony.com/doc/current/routing.html#generating-urls-in-commands 7 | #default_uri: http://localhost 8 | 9 | when@prod: 10 | framework: 11 | router: 12 | strict_requirements: null 13 | -------------------------------------------------------------------------------- /api/src/InputFilter/CleanText.php: -------------------------------------------------------------------------------- 1 | 2 |
3 |

4 | {{ title }} 5 |

6 | {{ error }} 7 |
8 | 9 | 10 | 18 | -------------------------------------------------------------------------------- /api/src/Validator/Period/AssertNotOverlappingWithOtherPeriods.php: -------------------------------------------------------------------------------- 1 | { 9 | cleanup() 10 | }) 11 | 12 | expect.addSnapshotSerializer(snapshotSerializer) 13 | -------------------------------------------------------------------------------- /api/docker/php/conf.d/api-platform.ini: -------------------------------------------------------------------------------- 1 | expose_php = 0 2 | date.timezone = UTC 3 | apc.enable_cli = 1 4 | session.use_strict_mode = 1 5 | zend.detect_unicode = 0 6 | 7 | ; https://symfony.com/doc/current/performance.html 8 | realpath_cache_size = 4096K 9 | realpath_cache_ttl = 600 10 | opcache.interned_strings_buffer = 16 11 | opcache.max_accelerated_files = 20000 12 | opcache.memory_consumption = 256 13 | opcache.enable_file_override = 1 -------------------------------------------------------------------------------- /api/src/Serializer/NoCachingSupportTrait.php: -------------------------------------------------------------------------------- 1 | false]; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /api/tests/Api/SnapshotTests/__snapshots__/ResponseSnapshotTest__testGetItemMatchesStructure with data set activity_progress_labels__1.json: -------------------------------------------------------------------------------- 1 | { 2 | "_links": { 3 | "camp": { 4 | "href": "escaped_value" 5 | }, 6 | "self": { 7 | "href": "escaped_value" 8 | } 9 | }, 10 | "id": "escaped_value", 11 | "position": "escaped_value", 12 | "title": "escaped_value" 13 | } 14 | -------------------------------------------------------------------------------- /print/README.md: -------------------------------------------------------------------------------- 1 | # print 2 | 3 | ## Build Setup 4 | 5 | ```bash 6 | # install dependencies 7 | $ npm install 8 | 9 | # serve with hot reload at localhost 10 | $ npm run dev 11 | 12 | # build for production and launch server 13 | $ npm run build 14 | $ npm run start 15 | 16 | # generate static project 17 | $ npm run generate 18 | ``` 19 | 20 | For detailed explanation on how things work, check out [Nuxt.js docs](https://nuxtjs.org). 21 | -------------------------------------------------------------------------------- /.helm/ecamp3/files/hook_db_restore/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | restore-backup: 3 | build: 4 | context: ../db-backup-restore-image 5 | dockerfile: Dockerfile 6 | volumes: 7 | - ./restore-backup.sh:/restore-backup.sh 8 | - ./update-support-email.sh:/update-support-email.sh 9 | command: 10 | - sh 11 | - "-x" 12 | - /restore-backup.sh 13 | env_file: .env 14 | network_mode: host 15 | -------------------------------------------------------------------------------- /api/config/packages/stof_doctrine_extensions.yaml: -------------------------------------------------------------------------------- 1 | # Read the documentation: https://symfony.com/doc/current/bundles/StofDoctrineExtensionsBundle/index.html 2 | # See the official DoctrineExtensions documentation for more details: https://github.com/Atlantic18/DoctrineExtensions/tree/master/doc/ 3 | stof_doctrine_extensions: 4 | default_locale: en_US 5 | orm: 6 | default: 7 | timestampable: true 8 | sortable: true 9 | -------------------------------------------------------------------------------- /api/docker/php/conf.d/api-platform.dev.ini: -------------------------------------------------------------------------------- 1 | ; See https://docs.docker.com/desktop/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host 2 | ; See https://github.com/docker/for-linux/issues/264 3 | ; The `client_host` below may optionally be replaced with `discover_client_host=yes` 4 | ; Add `start_with_request=yes` to start debug session on each request 5 | memory_limit = ${PHP_MEMORY_LIMIT:-} 6 | xdebug.client_host = host.docker.internal 7 | -------------------------------------------------------------------------------- /api/tests/Api/SnapshotTests/__snapshots__/ResponseSnapshotTest__testGetItemMatchesStructure with data set day_responsibles__1.json: -------------------------------------------------------------------------------- 1 | { 2 | "_links": { 3 | "campCollaboration": { 4 | "href": "escaped_value" 5 | }, 6 | "day": { 7 | "href": "escaped_value" 8 | }, 9 | "self": { 10 | "href": "escaped_value" 11 | } 12 | }, 13 | "id": "escaped_value" 14 | } 15 | -------------------------------------------------------------------------------- /api/translations/email+intl-icu.en.json: -------------------------------------------------------------------------------- 1 | { 2 | "inviteToCamp": { 3 | "subject": "[eCamp v3] You were invited to collaborate in camp \"{campTitle}\"" 4 | }, 5 | "userActivation": { 6 | "subject": "Welcome to eCamp v3" 7 | }, 8 | "passwordReset": { 9 | "subject": "[eCamp v3] Password reset" 10 | }, 11 | "emailVerification": { 12 | "subject": "[eCamp v3] Verify email address" 13 | } 14 | } -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | # frontend 2 | 3 | ## Project setup 4 | 5 | ``` 6 | npm install 7 | ``` 8 | 9 | ### Compiles and hot-reloads for development 10 | 11 | ``` 12 | npm run serve 13 | ``` 14 | 15 | ### Compiles and minifies for production 16 | 17 | ``` 18 | npm run build 19 | ``` 20 | 21 | ### Lints and fixes files 22 | 23 | ``` 24 | npm run lint 25 | ``` 26 | 27 | ### Run your unit tests 28 | 29 | ``` 30 | npm run test:unit 31 | ``` 32 | -------------------------------------------------------------------------------- /.ops/ecamp3-logging/files/kibana/restore-kibana-objects.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SCRIPT_DIR=$(realpath "$(dirname "$0")") 4 | 5 | KIBANA_HOST=${KIBANA_HOST:-localhost:5601} 6 | 7 | tmp_file=/tmp/$(uuidgen).ndjson 8 | 9 | cat $SCRIPT_DIR/kibana-objects.ndjson | jq -c > $tmp_file 10 | 11 | curl -X POST "$KIBANA_HOST/api/saved_objects/_import?createNewCopies=false&overwrite=true" \ 12 | -H "kbn-xsrf: true" \ 13 | --form file=@$tmp_file 14 | -------------------------------------------------------------------------------- /api/src/InputFilter/Trim.php: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /print/store/README.md: -------------------------------------------------------------------------------- 1 | # STORE 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your Vuex Store files. 6 | Vuex Store option is implemented in the Nuxt.js framework. 7 | 8 | Creating a file in this directory automatically activates the option in the framework. 9 | 10 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/vuex-store). 11 | -------------------------------------------------------------------------------- /api/src/Validator/ContentNode/AssertContentTypeCompatible.php: -------------------------------------------------------------------------------- 1 | request('POST', '/profiles', ['json' => []]); 13 | 14 | $this->assertResponseStatusCodeSame(405); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /e2e/specs/httpCache/root.cy.js: -------------------------------------------------------------------------------- 1 | const user1 = 'test@example.com' 2 | const user2 = 'castor@example.com' 3 | it('caches the root endpoint', () => { 4 | const uri = '/api/index' 5 | 6 | Cypress.session.clearAllSavedSessions() 7 | cy.login(user1) 8 | 9 | // first request is a cache miss 10 | cy.expectCacheMiss(uri) 11 | 12 | // second request is a cache hit 13 | cy.expectCacheHit(uri) 14 | 15 | cy.login(user2) 16 | cy.expectCacheMiss(uri) 17 | }) 18 | -------------------------------------------------------------------------------- /frontend/src/locales/it-CH-scout.json: -------------------------------------------------------------------------------- 1 | { 2 | "contentNode": { 3 | "storycontext": { 4 | "name": "Filo rosso" 5 | } 6 | }, 7 | "entity": { 8 | "user": { 9 | "fields": { 10 | "nickname": "Nome del Scout" 11 | } 12 | } 13 | }, 14 | "global": { 15 | "language": "Italiano (Scout)" 16 | }, 17 | "views": { 18 | "camp": { 19 | "story": { 20 | "title": "Filo rosso" 21 | } 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /.helm/ecamp3/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "app.serviceAccountName" . }} 6 | labels: 7 | {{- include "app.commonSelectorLabels" . | nindent 4 }} 8 | {{- include "app.commonLabels" . | nindent 4 }} 9 | {{- with .Values.serviceAccount.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | {{- end }} 14 | -------------------------------------------------------------------------------- /api/templates/emails/verifyMailAdress.de.text.twig: -------------------------------------------------------------------------------- 1 | Änderung deiner E-Mail-Adresse 2 | 3 | Hallo {{ name | raw }}, 4 | 5 | Wir haben die Anfrage erhalten, deine E-Mail-Adresse bei eCamp zu ändern. 6 | 7 | Falls du das warst, bestätige deine neue E-Mail-Adresse, indem du den nachfolgenden Link öffnest: 8 | {{ url | raw }} 9 | 10 | Alte E-Mail-Adresse: {{ oldMail | raw }} 11 | Neue E-Mail-Adresse: {{ newMail | raw }} 12 | 13 | Beste Grüsse, 14 | dein eCamp-Team 15 | -------------------------------------------------------------------------------- /print/assets/typography.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 10pt; 3 | } 4 | 5 | /* override standard styling from @tailwindcss/typography */ 6 | 7 | .tw-prose :where(.tw-prose > :first-child):not(:where([class~='tw-not-prose'] *)) { 8 | margin-top: 0 !important; 9 | } 10 | 11 | .tw-prose { 12 | line-height: 1.5; 13 | max-width: 100%; 14 | } 15 | 16 | .body { 17 | color: #404040; /* same as variable --tw-prose-body from class .tw-prose-neutral (neutral-700) */ 18 | } 19 | -------------------------------------------------------------------------------- /.helm/ecamp3/templates/print_browserless_secrets.yaml: -------------------------------------------------------------------------------- 1 | {{ $secretName := include "print-browserless.name" . }} 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: {{ $secretName }} 6 | labels: 7 | {{- include "print.selectorLabels" . | nindent 4 }} 8 | {{- include "app.commonLabels" . | nindent 4 }} 9 | type: Opaque 10 | data: 11 | {{- include "gen.secret" (dict "namespace" .Release.Namespace "secretName" $secretName "key" "BROWSERLESS_TOKEN") | nindent 2 }} 12 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "php-cs-fixer.executablePath": "${workspaceFolder}/api/vendor/bin/php-cs-fixer", 3 | "php-cs-fixer.config": "./api/.php-cs-fixer.php", 4 | "javascript.format.enable": false, 5 | "eslint.format.enable": false, 6 | "phpunit.files": "api/tests/**/*Test.php", 7 | "phpunit.args": [ 8 | "-capi/phpunit.nodocker.xml" 9 | ], 10 | "eslint.workingDirectories": [ 11 | "./frontend", 12 | "./print" 13 | ] 14 | } -------------------------------------------------------------------------------- /e2e/tasks/getPdfProperties.js: -------------------------------------------------------------------------------- 1 | const pdfjsLib = require('pdfjs-dist/legacy/build/pdf.mjs') 2 | const { readFileSync } = require('node:fs') 3 | 4 | async function getPdfProperties(path) { 5 | const data = new Uint8Array(readFileSync(path)) 6 | 7 | const loadDocument = pdfjsLib.getDocument({ data: data }) 8 | const pdfDocument = await loadDocument.promise 9 | return { 10 | numPages: pdfDocument.numPages, 11 | } 12 | } 13 | 14 | module.exports = { getPdfProperties } 15 | -------------------------------------------------------------------------------- /frontend/src/views/admin/Checklist.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 22 | -------------------------------------------------------------------------------- /pdf/src/campPrint/tableOfContents/entry/Summary.vue: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /common/assets/logos/JSLogo.svg: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /frontend/src/locales/rm-CH-scout.json: -------------------------------------------------------------------------------- 1 | { 2 | "contentNode": { 3 | "storycontext": { 4 | "name": "Fil cotschen" 5 | } 6 | }, 7 | "entity": { 8 | "user": { 9 | "fields": { 10 | "nickname": "Num da battasendas" 11 | } 12 | } 13 | }, 14 | "global": { 15 | "language": "Rumantsch (Battasendas)" 16 | }, 17 | "views": { 18 | "camp": { 19 | "story": { 20 | "title": "Fil cotschen" 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /print/plugins/dayjs.js: -------------------------------------------------------------------------------- 1 | import dayjs from '@/common/helpers/dayjs.js' 2 | 3 | // avoid tree-shaking of dayjs/locales 4 | import('dayjs/locale/en-gb') 5 | import('dayjs/locale/de') 6 | import('dayjs/locale/de-ch') 7 | import('dayjs/locale/fr') 8 | import('dayjs/locale/fr-ch') 9 | import('dayjs/locale/it') 10 | import('dayjs/locale/it-ch') 11 | 12 | export default defineNuxtPlugin((nuxtApp) => { 13 | // now available on `nuxtApp.$injected` 14 | nuxtApp.provide('date', dayjs) 15 | }) 16 | -------------------------------------------------------------------------------- /api/src/Validator/AssertContainsAtLeastOneManager.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/components/form/api/ApiForm.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 22 | -------------------------------------------------------------------------------- /print/public/README.md: -------------------------------------------------------------------------------- 1 | # STATIC 2 | 3 | **This directory is not required, you can delete it if you don't want to use it.** 4 | 5 | This directory contains your static files. 6 | Each file inside this directory is mapped to `/`. 7 | Thus you'd want to delete this README.md before deploying to production. 8 | 9 | Example: `/static/robots.txt` is mapped as `/robots.txt`. 10 | 11 | More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#static). 12 | -------------------------------------------------------------------------------- /.ops/ops-dashboard/templates/kubernetes_dashboard_cluster_admin_cluster_role_binding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: kubernetes-dashboard-admin-user 5 | namespace: {{ .Release.Namespace }} 6 | roleRef: 7 | apiGroup: rbac.authorization.k8s.io 8 | kind: ClusterRole 9 | name: cluster-admin 10 | subjects: 11 | - kind: ServiceAccount 12 | name: kubernetes-dashboard-admin-user 13 | namespace: {{ .Release.Namespace }} 14 | -------------------------------------------------------------------------------- /.helm/ecamp3/templates/browserless_configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: {{ include "browserless.name" . }}-configmap 5 | labels: 6 | {{- include "browserless.selectorLabels" . | nindent 4 }} 7 | {{- include "app.commonLabels" . | nindent 4 }} 8 | data: 9 | CONCURRENT: {{ .Values.browserless.maxConcurrentSessions | quote }} 10 | TIMEOUT: {{ .Values.browserless.connectionTimeout | quote }} 11 | QUEUED: {{ .Values.browserless.maxQueueLength | quote }} 12 | -------------------------------------------------------------------------------- /api/src/Serializer/Normalizer/RelatedCollectionLink.php: -------------------------------------------------------------------------------- 1 | relatedEntity; 11 | } 12 | 13 | public function getParams(): array { 14 | return $this->params; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /pdf/src/renderer/__tests__/createCircularReplacer.js: -------------------------------------------------------------------------------- 1 | export function createCircularReplacer() { 2 | const ancestors = [] 3 | return function (key, value) { 4 | if (typeof value !== 'object' || value === null) { 5 | return value 6 | } 7 | while (ancestors.length > 0 && ancestors.at(-1) !== this) { 8 | ancestors.pop() 9 | } 10 | if (ancestors.includes(value)) { 11 | return '[Circular]' 12 | } 13 | ancestors.push(value) 14 | return value 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /print/components/Toc/TocToc.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 19 | -------------------------------------------------------------------------------- /api/tests/Api/ContentNodes/ContentNode/CreateContentNodeTest.php: -------------------------------------------------------------------------------- 1 | request('POST', '/content_nodes', ['json' => []]); 13 | $this->assertResponseStatusCodeSame(405); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /api/tests/Api/SnapshotTests/__snapshots__/ResponseSnapshotTest__testGetItemMatchesStructure with data set checklists__1.json: -------------------------------------------------------------------------------- 1 | { 2 | "_links": { 3 | "camp": { 4 | "href": "escaped_value" 5 | }, 6 | "checklistItems": { 7 | "href": "escaped_value" 8 | }, 9 | "self": { 10 | "href": "escaped_value" 11 | } 12 | }, 13 | "id": "escaped_value", 14 | "isPrototype": "escaped_value", 15 | "name": "escaped_value" 16 | } 17 | -------------------------------------------------------------------------------- /api/tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | bootEnv(dirname(__DIR__).'/.env'); 10 | } 11 | 12 | if ($_SERVER['APP_DEBUG']) { 13 | umask(0000); 14 | } 15 | 16 | require dirname(__DIR__).'/vendor/autoload.php'; 17 | 18 | set_exception_handler([new ErrorHandler(), 'handleException']); 19 | -------------------------------------------------------------------------------- /common/locales/de-CH-scout.json: -------------------------------------------------------------------------------- 1 | { 2 | "entity": { 3 | "camp": { 4 | "fields": { 5 | "courseKind": "Kursbezeichnung (bei J+S Kurs: J+S Bezeichnung)", 6 | "courseNumber": "Kursnummer", 7 | "printYSLogoOnPicasso": "J+S-Logo auf Grobprogramm drucken (bei J+S-Kursen aktivieren)", 8 | "trainingAdvisorName": "Bürgerlicher Name von LKB" 9 | } 10 | }, 11 | "profile": { 12 | "fields": { 13 | "nickname": "Pfadiname" 14 | } 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /print/components/Toc/TocCover.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 19 | -------------------------------------------------------------------------------- /api/migrations/schema/checklists/helpers.php: -------------------------------------------------------------------------------- 1 | $statement->build(), $parser->statements); 13 | 14 | return str_replace('`', '"', $parsed_statements); 15 | } 16 | -------------------------------------------------------------------------------- /api/tests/Api/Days/DeleteDayTest.php: -------------------------------------------------------------------------------- 1 | request('DELETE', '/days/'.$day->getId()); 14 | 15 | $this->assertResponseStatusCodeSame(405); // method not allowed 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /print/components/generic/YSLogo.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 21 | -------------------------------------------------------------------------------- /frontend/src/views/admin/Checklists.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 20 | -------------------------------------------------------------------------------- /api/src/Util/IdGenerator.php: -------------------------------------------------------------------------------- 1 | ({ 2 | params: ['min'], 3 | /** 4 | * 5 | * @param {string} value value of a float number 6 | * @param number min Comparison value in string format 'HH:mm' 7 | * @returns {boolean} validation result 8 | */ 9 | validate: (value, { min }) => { 10 | return parseFloat(value) > min 11 | }, 12 | message: (field, { min }) => { 13 | return i18n.tc('global.validation.greaterThan', 0, { 14 | min: min, 15 | }) 16 | }, 17 | }) 18 | -------------------------------------------------------------------------------- /.github/actions/setup-helmfile/action.yaml: -------------------------------------------------------------------------------- 1 | name: 'Setup helmfile' 2 | description: 'Sets up helmfile in /usr/local/bin/helmfile' 3 | runs: 4 | using: "composite" 5 | steps: 6 | - name: install helmfile 7 | run: | 8 | curl -L https://github.com/helmfile/helmfile/releases/download/v1.1.3/helmfile_1.1.3_linux_amd64.tar.gz -o helmfile.tar.gz 9 | tar -xvf /tmp/helmfile.tar.gz 10 | mv helmfile /usr/local/bin 11 | chmod +x /usr/local/bin/helmfile 12 | working-directory: /tmp 13 | shell: bash 14 | -------------------------------------------------------------------------------- /.helm/ecamp3/templates/tests/test-connection.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: "{{ include "api.name" . }}-test-connection" 5 | labels: 6 | {{- include "app.commonSelectorLabels" . | nindent 4 }} 7 | {{- include "app.commonLabels" . | nindent 4 }} 8 | annotations: 9 | "helm.sh/hook": test 10 | spec: 11 | containers: 12 | - name: wget 13 | image: busybox 14 | command: ['wget'] 15 | args: ['{{ include "api.name" . }}:{{ .Values.api.service.port }}'] 16 | restartPolicy: Never 17 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /components.d.ts 4 | /data 5 | /dist 6 | 7 | selenium-debug.log 8 | 9 | # local env files 10 | .env.local 11 | .env.*.local 12 | 13 | # Auto-generated files 14 | public/twemoji/ 15 | 16 | # Log files 17 | npm-debug.log* 18 | yarn-debug.log* 19 | yarn-error.log* 20 | 21 | # Editor directories and files 22 | .idea 23 | .vscode 24 | *.suo 25 | *.ntvs* 26 | *.njsproj 27 | *.sln 28 | *.sw* 29 | 30 | # yalc 31 | .yalc 32 | yalc.lock 33 | 34 | # Sentry Auth Token 35 | .env.sentry-build-plugin 36 | -------------------------------------------------------------------------------- /pdf/src/campPrint/TocSectionStartMarker.vue: -------------------------------------------------------------------------------- 1 | 6 | 15 | 23 | -------------------------------------------------------------------------------- /.helm/ecamp3/files/db_backup_job/README.md: -------------------------------------------------------------------------------- 1 | # db_backup_job 2 | 3 | This folder contains the files used in the db_backup_job.\ 4 | It also contains a docker-compose.yml file to easily test the [create-backup.sh](create-backup.sh) locally. 5 | 6 | 1. Copy the [.env-example](.env-example) file to [.env](.env) 7 | 8 | ```shell 9 | cp .env-example .env 10 | ``` 11 | 12 | 2. Fill in the variables of [.env](.env) 13 | 14 | 3. Run the image with the script 15 | 16 | ```shell 17 | docker compose run --rm create-backup 18 | ``` 19 | -------------------------------------------------------------------------------- /frontend/src/components/collaborator/isOwnCampCollaboration.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef Collaborator { 3 | * user: () => { id: string }, 4 | * } 5 | * 6 | * @typedef Auth { 7 | * user: { id: string }, 8 | * } 9 | * 10 | * @param {Collaborator} collaborator 11 | * @param {Auth} auth 12 | * @returns {boolean} 13 | */ 14 | export default function isOwnCampCollaboration(collaborator, auth) { 15 | if (!(typeof collaborator.user === 'function')) { 16 | return false 17 | } 18 | return auth.user?.id === collaborator.user().id 19 | } 20 | -------------------------------------------------------------------------------- /api/migrations/prod-data/helpers.php: -------------------------------------------------------------------------------- 1 | $statement->build(), $parser->statements); 14 | 15 | return str_replace('`', '"', $parsed_statements); 16 | } 17 | -------------------------------------------------------------------------------- /api/tests/State/CampCollaborationTestTrait.php: -------------------------------------------------------------------------------- 1 | [CampCollaboration::STATUS_INACTIVE], 12 | CampCollaboration::STATUS_ESTABLISHED => [CampCollaboration::STATUS_ESTABLISHED], 13 | ]; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /common/helpers/__tests__/userDisplayName.spec.js: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import userDisplayName from '../userDisplayName.js' 3 | 4 | describe('userDisplayName', () => { 5 | it.each([ 6 | [{ id: 'fffffff' }, ''], 7 | [{ displayName: 'test' }, 'test'], 8 | [{ displayName: 'test', _meta: {} }, 'test'], 9 | [{ _meta: { loading: true } }, ''], 10 | [null, ''], 11 | [undefined, ''], 12 | ])('maps %p to %p', (input, expected) => { 13 | expect(userDisplayName(input)).toEqual(expected) 14 | }) 15 | }) 16 | -------------------------------------------------------------------------------- /api/src/Validator/MaterialItemUpdateGroupSequence.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class NotAResource { 13 | public function __construct( 14 | private $foo, 15 | private $bar 16 | ) {} 17 | 18 | public function getFoo() { 19 | return $this->foo; 20 | } 21 | 22 | public function getBar() { 23 | return $this->bar; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.ops/ingress/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -ea 4 | 5 | SCRIPT_DIR=$(realpath "$(dirname "$0")") 6 | cd $SCRIPT_DIR 7 | 8 | helm dep build 9 | 10 | if [ $1 = "deploy" ]; then 11 | # to debug: --dry-run --debug 12 | helm upgrade --install ecamp3-ingress --namespace=ingress-nginx --create-namespace $SCRIPT_DIR 13 | exit 0 14 | fi 15 | 16 | if [ $1 = "diff" ]; then 17 | helm template \ 18 | --namespace ingress-nginx --no-hooks --skip-tests ecamp3-ingress \ 19 | $SCRIPT_DIR | kubectl diff --namespace ingress-nginx -f - 20 | exit 0 21 | fi 22 | -------------------------------------------------------------------------------- /api/src/Validator/ScheduleEntryPostGroupSequence.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | #[ORM\Entity] 15 | class ContainNonResource extends BaseEntity { 16 | /** 17 | * @var NotAResource 18 | */ 19 | public $notAResource; 20 | 21 | /** 22 | * @var NotAResource[] 23 | */ 24 | public $collectionOfNotAResource; 25 | } 26 | -------------------------------------------------------------------------------- /crowdin.yml: -------------------------------------------------------------------------------- 1 | pull_request_title: Update translations from Crowdin 2 | commit_message: Update %language% translations 3 | files: 4 | - source: /frontend/src/locales/en.json 5 | translation: /frontend/src/locales/%locale%.json 6 | - source: /common/locales/en.json 7 | translation: /common/locales/%locale%.json 8 | - source: /api/translations/email+intl-icu.en.json 9 | translation: /api/translations/email+intl-icu.%locale%.json 10 | - source: /api/translations/validators.en.yml 11 | translation: /api/translations/validators.%locale_with_underscore%.yml 12 | -------------------------------------------------------------------------------- /frontend/src/components/campAdmin/DialogMaterialListForm.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 25 | -------------------------------------------------------------------------------- /api/migrations/dev-data/Version202201230531.php: -------------------------------------------------------------------------------- 1 | request('POST', '/days', ['json' => [ 13 | 'name' => 'something', 14 | ], 'headers' => ['Content-Type' => 'application/merge-patch+json']]); 15 | 16 | $this->assertResponseStatusCodeSame(405); // method not allowed 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /frontend/src/components/print/print-nuxt/DownloadNuxtPdfButton.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 20 | -------------------------------------------------------------------------------- /api/src/Kernel.php: -------------------------------------------------------------------------------- 1 | addCompilerPass(new JWTOAuthStateCompilerPass()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /api/tests/Api/ContentNodes/ContentNode/DeleteContentNodeTest.php: -------------------------------------------------------------------------------- 1 | request('DELETE', '/content_nodes/'.$contentNode->getId()); 14 | $this->assertResponseStatusCodeSame(405); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /frontend/src/components/form/ServerError.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 23 | -------------------------------------------------------------------------------- /frontend/src/plugins/index.js: -------------------------------------------------------------------------------- 1 | export { default as vuetifyLoader } from './vuetify' 2 | export { default as storeLoader } from './store' 3 | export { default as auth } from './auth' 4 | export { default as formBaseComponents } from './formBaseComponents' 5 | export { default as ignoreNativeBindingWarnMessages } from './ignoreNativeBindingWarnMessages' 6 | export { default as i18n } from './i18n' 7 | export { default as veeValidate } from './veeValidate' 8 | export { default as dayjs } from './dayjs' 9 | export { default as color } from './color' 10 | export { head, unhead } from './head' 11 | -------------------------------------------------------------------------------- /print/components/scheduleEntry/contentNode/ColumnLayout.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 21 | -------------------------------------------------------------------------------- /.ops/ecamp3-logging/templates/elasticsearch/elasticsearch_service.yaml: -------------------------------------------------------------------------------- 1 | kind: Service 2 | apiVersion: v1 3 | metadata: 4 | name: elasticsearch 5 | namespace: {{ .Release.Namespace }} 6 | labels: 7 | app: elasticsearch 8 | {{- include "app.commonLabels" . | nindent 4 }} 9 | {{- include "app.commonSelectorLabels" . | nindent 4 }} 10 | spec: 11 | selector: 12 | app: elasticsearch 13 | {{- include "app.commonSelectorLabels" . | nindent 4 }} 14 | clusterIP: None 15 | ports: 16 | - port: 9200 17 | name: rest 18 | - port: 9300 19 | name: inter-node 20 | -------------------------------------------------------------------------------- /api/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | .cache 3 | /docker/db/data 4 | 5 | ###> symfony/framework-bundle ### 6 | /.env.local 7 | /.env.local.php 8 | /.env.*.local 9 | /config/secrets/prod/prod.decrypt.private.php 10 | /public/bundles/ 11 | /var/ 12 | /vendor/ 13 | ###< symfony/framework-bundle ### 14 | 15 | ###> friendsofphp/php-cs-fixer ### 16 | /.php-cs-fixer.cache 17 | ###< friendsofphp/php-cs-fixer ### 18 | ###> lexik/jwt-authentication-bundle ### 19 | /config/jwt/*.pem 20 | ###< lexik/jwt-authentication-bundle ### 21 | 22 | ###> phpunit/phpunit ### 23 | .phpunit.cache 24 | ###< phpunit/phpunit ### 25 | -------------------------------------------------------------------------------- /common/helpers/activityResponsibles.js: -------------------------------------------------------------------------------- 1 | import campCollaborationDisplayName from './campCollaborationDisplayName.js' 2 | 3 | /** 4 | * Returns a display name for a camp collaboration based on its status 5 | */ 6 | const activityResponsiblesCommaSeparated = (activity, tc) => { 7 | if (!activity) return '' 8 | 9 | return activity 10 | .activityResponsibles() 11 | .items.map((activityResponsible) => 12 | campCollaborationDisplayName(activityResponsible.campCollaboration(), tc) 13 | ) 14 | .join(', ') 15 | } 16 | 17 | export { activityResponsiblesCommaSeparated } 18 | -------------------------------------------------------------------------------- /frontend/src/components/activity/content/layout/LayoutItem.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | 17 | 26 | -------------------------------------------------------------------------------- /frontend/src/components/layout/TextAlignBaseline.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 13 | 14 | 29 | -------------------------------------------------------------------------------- /common/eslint-local-rules/packageDirectory.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import fs from "fs"; 3 | 4 | export function packageDirectory(filename) { 5 | const { root } = path.parse(filename) 6 | 7 | let directory = filename 8 | while (directory !== root) { 9 | directory = path.dirname(directory) 10 | 11 | try { 12 | if (fs.statSync(path.resolve(directory, 'package.json')).isFile()) { 13 | return directory 14 | } 15 | } catch { 16 | // Ignore, try going up to the next directory 17 | } 18 | } 19 | 20 | return '' 21 | } 22 | -------------------------------------------------------------------------------- /frontend/src/views/camp/checklist/Checklist.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 25 | -------------------------------------------------------------------------------- /pdf/src/campPrint/tableOfContents/entry/Story.vue: -------------------------------------------------------------------------------- 1 | 7 | 17 | -------------------------------------------------------------------------------- /api/tests/Api/ContentTypes/DeleteContentTypeTest.php: -------------------------------------------------------------------------------- 1 | request('DELETE', '/content_types/'.$contentType->getId()); 14 | 15 | $this->assertResponseStatusCodeSame(405); // method not allowed 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /common/eslint-local-rules/__tests__/packageDirectory.spec.js: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from 'vitest' 2 | import { packageDirectory } from '../packageDirectory.js' 3 | import path from 'path' 4 | import fs from 'fs' 5 | 6 | describe('packageDirectory', () => { 7 | it('resolves the location of the closest package.json', () => { 8 | const packageJsonFile = path.resolve(__dirname, '../../package.json') 9 | fs.writeFileSync(packageJsonFile, '{}') 10 | expect(packageDirectory(__dirname)).toEqual(path.resolve(__dirname, '../..')) 11 | fs.unlinkSync(packageJsonFile) 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /frontend/src/components/program/picasso/dateHelperVCalendar.js: -------------------------------------------------------------------------------- 1 | import dayjs from '@/common/helpers/dayjs.js' 2 | 3 | // converts a timestamp (local timezone) into ISO String format (UTC timezone) 4 | function timestampToUtcString(timestamp) { 5 | return dayjs.utc(dayjs(timestamp).format('YYYY-MM-DD HH:mm')).format() 6 | } 7 | 8 | // converts ISO String format (UTC timezone) into a timestamp (local timezone) 9 | function utcStringToTimestamp(string) { 10 | return dayjs(dayjs.utc(string).format('YYYY-MM-DD HH:mm')).valueOf() 11 | } 12 | 13 | export { timestampToUtcString, utcStringToTimestamp } 14 | -------------------------------------------------------------------------------- /.ops/ecamp3-logging/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Common labels 3 | */}} 4 | {{- define "app.commonLabels" -}} 5 | chart: {{ .Chart.Name }} 6 | helm.sh/chart: {{ .Chart.Name }} 7 | {{- if .Chart.AppVersion }} 8 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 9 | {{- end }} 10 | app.kubernetes.io/managed-by: {{ .Release.Service }} 11 | {{- end }} 12 | 13 | {{/* 14 | Common selector labels 15 | */}} 16 | {{- define "app.commonSelectorLabels" -}} 17 | app.kubernetes.io/instance: {{ .Release.Name }} 18 | app.kubernetes.io/part-of: {{ .Chart.Name }} 19 | chart: {{ .Chart.Name }} 20 | {{- end }} 21 | -------------------------------------------------------------------------------- /.ops/ops-dashboard/Chart.lock: -------------------------------------------------------------------------------- 1 | dependencies: 2 | - name: oauth2-proxy 3 | repository: https://oauth2-proxy.github.io/manifests 4 | version: 7.18.0 5 | - name: kubernetes-dashboard 6 | repository: https://kubernetes.github.io/dashboard/ 7 | version: 7.14.0 8 | - name: oauth2-proxy 9 | repository: https://oauth2-proxy.github.io/manifests 10 | version: 7.18.0 11 | - name: oauth2-proxy 12 | repository: https://oauth2-proxy.github.io/manifests 13 | version: 7.18.0 14 | digest: sha256:7ec11af29604ef6739640a976d8276f6d83414bb27287815f0e0472d9bb9604a 15 | generated: "2025-11-06T17:09:52.775601394Z" 16 | -------------------------------------------------------------------------------- /api/src/State/CampCollaborationSendEmailTrait.php: -------------------------------------------------------------------------------- 1 | status && $data->getEmail()) { 11 | /** @var User $user */ 12 | $user = $this->security->getUser(); 13 | 14 | $this->mailService->sendInviteToCampMail($user, $data->camp, $data->inviteKey, $data->getEmail()); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /frontend/src/components/material/shortScheduleEntryDescription.js: -------------------------------------------------------------------------------- 1 | import { hourShort } from '@/common/helpers/dateHelperUTCFormatted.js' 2 | 3 | export default function shortScheduleEntryDescription(scheduleEntry, tc) { 4 | if (!scheduleEntry || scheduleEntry._meta.loading) return '' 5 | return ( 6 | scheduleEntry?.number || 7 | // For numbering style "none", display the activity title and day number instead 8 | tc('global.shortScheduleEntryDescription', 1, { 9 | dayNumber: scheduleEntry.dayNumber, 10 | startTime: hourShort(scheduleEntry.start, tc), 11 | }) 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /.helm/ecamp3/files/hook_db_restore/update-support-email.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | tmpfile=$(mktemp) 4 | 5 | cat << 'EOF' | tee -a $tmpfile 6 | BEGIN; 7 | 8 | WITH profile as (SELECT id from profile WHERE email = 'support@ecamp3.ch'), 9 | update_password as (UPDATE "user" SET password = '$2y$13$KTCSklVQHNvbwJQ3Awl8Ee7t0wJB1gfRBXDANeQlBblqwJ4wgOEmC' WHERE profileid = (SELECT id FROM profile)), 10 | update_email as (UPDATE "profile" SET email = 'test@example.com' WHERE id = (SELECT id FROM profile)) 11 | SELECT 1; 12 | 13 | COMMIT; 14 | 15 | EOF 16 | 17 | psql $DATABASE_URL -v ON_ERROR_STOP=1 < $tmpfile 18 | -------------------------------------------------------------------------------- /common/helpers/initials.js: -------------------------------------------------------------------------------- 1 | import runes from 'runes' 2 | 3 | /** 4 | * Returns two characters to display for a display name 5 | */ 6 | export default function (displayName) { 7 | if (!displayName) return '' 8 | 9 | let items = displayName.split(' ', 2) 10 | if (items.length === 1) { 11 | items = items.shift().split(/[,._-]/, 2) 12 | } 13 | if (items.length === 1) { 14 | return runes.substr(displayName, 0, 2).toUpperCase() 15 | } else { 16 | return ( 17 | runes.substr(items[0], 0, 1).toUpperCase() + 18 | runes.substr(items[1], 0, 1).toUpperCase() 19 | ) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.helm/ecamp3/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | docker-compose.yml 25 | README.md 26 | .env 27 | .env-example 28 | .env 29 | /deploy.sh 30 | /values.yaml 31 | /values.yaml.gotmpl 32 | /env.yaml -------------------------------------------------------------------------------- /api/config/packages/nelmio_cors.yaml: -------------------------------------------------------------------------------- 1 | nelmio_cors: 2 | defaults: 3 | origin_regex: true 4 | allow_credentials: true 5 | allow_origin: 6 | - http://localhost:3000 7 | - https://localhost:3000 8 | - http://127.0.0.1:3000 9 | - https://127.0.0.1:3000 10 | - '%env(CORS_ALLOW_ORIGIN)%' 11 | allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE'] 12 | allow_headers: ['Content-Type', 'Authorization', 'Accept'] 13 | expose_headers: [] 14 | max_age: 3600 15 | paths: 16 | '^/': null 17 | -------------------------------------------------------------------------------- /api/config/packages/prod/doctrine.yaml: -------------------------------------------------------------------------------- 1 | doctrine: 2 | orm: 3 | metadata_cache_driver: 4 | type: pool 5 | pool: doctrine.system_cache_pool 6 | query_cache_driver: 7 | type: pool 8 | pool: doctrine.system_cache_pool 9 | result_cache_driver: 10 | type: pool 11 | pool: doctrine.result_cache_pool 12 | 13 | framework: 14 | cache: 15 | pools: 16 | doctrine.result_cache_pool: 17 | adapter: cache.app 18 | doctrine.system_cache_pool: 19 | adapter: cache.system 20 | -------------------------------------------------------------------------------- /common/helpers/__tests__/userInitials.spec.js: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import userInitials from '../userInitials.js' 3 | 4 | describe('userInitials', () => { 5 | it.each([ 6 | [{}, ''], 7 | [null, ''], 8 | [undefined, ''], 9 | [{ id: 'fffffff' }, ''], 10 | [{ displayName: 'test' }, 'TE'], 11 | [{ displayName: 'test', _meta: {} }, 'TE'], 12 | [{ _meta: { loading: true } }, ''], 13 | [{ abbreviation: 'V3', displayName: 'test' }, 'V3'], 14 | ])('maps %o to "%s"', (input, expected) => { 15 | expect(userInitials(input)).toEqual(expected) 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /frontend/vue.config.js: -------------------------------------------------------------------------------- 1 | export const pluginOptions = { 2 | jestSerializer: { 3 | attributesToClear: ['id', 'for'], 4 | formatting: { 5 | indent_char: ' ', 6 | indent_inner_html: true, 7 | indent_size: 5, 8 | inline: [], 9 | sep: '\n', 10 | wrap_attributes: 'force-aligned', 11 | }, 12 | }, 13 | } 14 | 15 | export default { 16 | devServer: { 17 | useLocalIp: false, 18 | allowedHosts: ['ecamp3', 'localhost', '127.0.0.1'], 19 | }, 20 | 21 | transpileDependencies: ['vuetify'], 22 | pluginOptions, 23 | css: { 24 | sourceMap: true, 25 | }, 26 | } 27 | -------------------------------------------------------------------------------- /.ops/ecamp3-logging/templates/elasticsearch/remove_old_indexes_configmap.yaml: -------------------------------------------------------------------------------- 1 | {{- if not (.Values.elasticsearch.removeOldIndexes.maxIndexAge | empty) }} 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: remove-old-indexes 6 | namespace: {{ .Release.Namespace }} 7 | labels: 8 | app: elasticsearch 9 | {{- include "app.commonLabels" . | nindent 4 }} 10 | {{- include "app.commonSelectorLabels" . | nindent 4 }} 11 | data: 12 | remove-old-indexes.mjs: | 13 | {{ range .Files.Lines "files/elasticsearch/remove-old-indexes/src/remove-old-indexes.mjs" }} 14 | {{ . }}{{ end }} 15 | {{- end }} 16 | -------------------------------------------------------------------------------- /api/src/Validator/ColumnLayout/AssertColumWidthsSumTo12.php: -------------------------------------------------------------------------------- 1 | message = $message ?? $this->message; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /api/templates/emails/userActivation.en.html.twig: -------------------------------------------------------------------------------- 1 | {% set preheader = 'Welcome to eCamp v3' %} 2 | {% extends 'emails/baseLayout.twig' %} 3 | 4 | {% block content %} 5 |

Welcome to eCamp v3

6 |

Hi {{ name }},

7 |

8 | We have just now received your registration for eCamp.
9 | Confirm your email address by clicking on below link: 10 |

11 | 12 | {% with { title: 'Confirm', url: url } %} 13 | {% include 'emails/button.twig' %} 14 | {% endwith %} 15 | 16 |

17 | Cheers,
18 | your eCamp team 19 |

20 | {% endblock %} -------------------------------------------------------------------------------- /frontend/public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /frontend/src/components/dashboard/BooleanFilter.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | -------------------------------------------------------------------------------- /.ops/ecamp3-logging/files/kibana/dump-kibana-objects.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | SCRIPT_DIR=$(realpath "$(dirname "$0")") 6 | 7 | KIBANA_HOST=${KIBANA_HOST:-localhost:5601} 8 | 9 | curl -X POST $KIBANA_HOST/api/saved_objects/_export \ 10 | -H 'kbn-xsrf: true' \ 11 | -H 'Content-Type: application/json' \ 12 | -d ' 13 | { 14 | "type": [ 15 | "dashboard", 16 | "index-pattern", 17 | "search" 18 | ], 19 | "excludeExportDetails": true 20 | }' \ 21 | --silent \ 22 | | jq -S \ 23 | > $SCRIPT_DIR/kibana-objects.ndjson 24 | -------------------------------------------------------------------------------- /api/tests/Api/Comments/UpdateCommentTest.php: -------------------------------------------------------------------------------- 1 | request('PATCH', '/comments/'.$comment->getId(), ['json' => [], 'headers' => ['Content-Type' => 'application/merge-patch+json']]); 14 | 15 | $this->assertResponseStatusCodeSame(405); // method not allowed 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /api/tests/Api/ContentTypes/CreateContentTypeTest.php: -------------------------------------------------------------------------------- 1 | request('POST', '/content_types', ['json' => [ 13 | 'name' => 'something', 14 | ], 'headers' => ['Content-Type' => 'application/merge-patch+json']]); 15 | 16 | $this->assertResponseStatusCodeSame(405); // method not allowed 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /api/tests/Api/SnapshotTests/__snapshots__/ResponseSnapshotTest__testGetItemMatchesStructure with data set checklist_items__1.json: -------------------------------------------------------------------------------- 1 | { 2 | "_links": { 3 | "checklist": { 4 | "href": "escaped_value" 5 | }, 6 | "checklistNodes": [ 7 | { 8 | "href": "escaped_value" 9 | } 10 | ], 11 | "children": [], 12 | "parent": "escaped_value", 13 | "self": { 14 | "href": "escaped_value" 15 | } 16 | }, 17 | "id": "escaped_value", 18 | "position": "escaped_value", 19 | "text": "escaped_value" 20 | } 21 | -------------------------------------------------------------------------------- /frontend/docker-setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -euo pipefail 3 | 4 | BASEDIR=$(dirname "$0") 5 | PDF_DIST=$BASEDIR"/src/pdf" 6 | 7 | if [ ! -f "$PDF_DIST/pdf.js" ] || [ ! -f "$PDF_DIST/prepareInMainThread.js" ]; then 8 | # Copy dummy versions of the pdf build outputs, to make sure there is always something to import 9 | cp "$PDF_DIST/pdf.js.dist" "$PDF_DIST/pdf.js" 10 | cp "$PDF_DIST/prepareInMainThread.js.dist" "$PDF_DIST/prepareInMainThread.js" 11 | fi 12 | 13 | if [ "$CI" = 'true' ] ; then 14 | npm ci --verbose 15 | npm run build 16 | npm run preview 17 | else 18 | npm install 19 | npm run dev 20 | fi 21 | -------------------------------------------------------------------------------- /frontend/src/components/activity/content/contentTypeIcons.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Maps content type to mdi icon 3 | */ 4 | const contentTypeIcons = { 5 | checklist: 'mdi-clipboard-list-outline', 6 | columnLayout: 'mdi-view-column', 7 | laThematicArea: 'mdi-shape', 8 | learningObjectives: 'mdi-school', 9 | learningTopics: 'mdi-school', 10 | material: 'mdi-package-variant', 11 | notes: 'mdi-pen', 12 | responsiveLayout: 'mdi-view-compact', 13 | safetyConsiderations: 'mdi-security', 14 | storyboard: 'mdi-script-text-outline', 15 | storycontext: 'mdi-book-open-variant', 16 | } 17 | 18 | export default contentTypeIcons 19 | -------------------------------------------------------------------------------- /frontend/src/views/camp/material/SideBarMaterialLists.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 21 | -------------------------------------------------------------------------------- /api/tests/Api/SnapshotTests/__snapshots__/ResponseSnapshotTest__testGetItemMatchesStructure with data set comments__1.json: -------------------------------------------------------------------------------- 1 | { 2 | "_links": { 3 | "activity": { 4 | "href": "escaped_value" 5 | }, 6 | "author": { 7 | "href": "escaped_value" 8 | }, 9 | "camp": { 10 | "href": "escaped_value" 11 | }, 12 | "self": { 13 | "href": "escaped_value" 14 | } 15 | }, 16 | "createTime": "escaped_value", 17 | "id": "escaped_value", 18 | "orphanDescription": "escaped_value", 19 | "textHtml": "escaped_value" 20 | } 21 | -------------------------------------------------------------------------------- /frontend/src/plugins/veeValidate/lessThanOrEqual_date.js: -------------------------------------------------------------------------------- 1 | export default (dayjs, i18n) => ({ 2 | params: ['max'], 3 | /** 4 | * @param {string} value Dater value in local string format 5 | * @param {string} max comparison valye in local string format 6 | * @returns {bool} validation result 7 | */ 8 | validate: (value, { max }) => { 9 | const maxDate = dayjs.utc(max, 'L') 10 | const valueDate = dayjs.utc(value, 'L') 11 | return valueDate.diff(maxDate, 'day') <= 0 12 | }, 13 | message: (field, values) => 14 | i18n.tc('global.validation.lessThanOrEqual_date', 0, values), 15 | }) 16 | -------------------------------------------------------------------------------- /.github/workflows/pull-request-rules.yml: -------------------------------------------------------------------------------- 1 | name: PR (additional rules) 2 | 3 | on: 4 | pull_request: 5 | types: [opened, labeled, unlabeled, synchronize] 6 | merge_group: 7 | push: 8 | branches: 9 | - 'renovate/**' 10 | 11 | jobs: 12 | no-meeting-discuss-label: 13 | name: No "Meeting Discuss" label 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: mheap/github-action-required-labels@8afbe8ae6ab7647d0c9f0cfa7c2f939650d22509 # v5 17 | if: github.event_name == 'pull_request' 18 | with: 19 | mode: exactly 20 | count: 0 21 | labels: "Meeting Discuss" 22 | -------------------------------------------------------------------------------- /.helm/ecamp3/templates/browserless_service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.browserless.enabled }} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ include "browserless.name" . }} 6 | labels: 7 | {{- include "browserless.selectorLabels" . | nindent 4 }} 8 | {{- include "app.commonLabels" . | nindent 4 }} 9 | spec: 10 | type: {{ .Values.browserless.service.type }} 11 | ports: 12 | - port: {{ .Values.browserless.service.port }} 13 | targetPort: browserless-ws 14 | protocol: TCP 15 | name: browserless-ws 16 | selector: 17 | {{- include "browserless.selectorLabels" . | nindent 4 }} 18 | {{- end }} -------------------------------------------------------------------------------- /api/config/packages/prod/monolog.yaml: -------------------------------------------------------------------------------- 1 | monolog: 2 | handlers: 3 | main: 4 | type: fingers_crossed 5 | action_level: error 6 | handler: nested 7 | excluded_http_codes: [404, 405] 8 | buffer_size: 50 # How many messages should be saved? Prevent memory leaks 9 | nested: 10 | type: stream 11 | path: php://stderr 12 | level: debug 13 | formatter: monolog.formatter.json 14 | console: 15 | type: console 16 | process_psr_3_messages: false 17 | channels: ["!event", "!doctrine"] 18 | -------------------------------------------------------------------------------- /api/src/Entity/UserCamp.php: -------------------------------------------------------------------------------- 1 | ({ 2 | params: ['min'], 3 | /** 4 | * @param {string} value Dater value in local string format 5 | * @param {string} min comparison valye in local string format 6 | * @returns {bool} validation result 7 | */ 8 | validate: (value, { min }) => { 9 | const minDate = dayjs.utc(min, 'L') 10 | const valueDate = dayjs.utc(value, 'L') 11 | return valueDate.diff(minDate, 'day') >= 0 12 | }, 13 | message: (field, values) => 14 | i18n.tc('global.validation.greaterThanOrEqual_date', 0, values), 15 | }) 16 | -------------------------------------------------------------------------------- /pdf/src/campPrint/tableOfContents/entry/Toc.vue: -------------------------------------------------------------------------------- 1 | 7 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /api/src/Doctrine/NameSpaceIgnoringVersionComparator.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | 25 | -------------------------------------------------------------------------------- /frontend/src/locales/fr-CH-scout.json: -------------------------------------------------------------------------------- 1 | { 2 | "components": { 3 | "print": { 4 | "printConfigurator": { 5 | "config": { 6 | "Story": "Fil rouge" 7 | } 8 | } 9 | } 10 | }, 11 | "contentNode": { 12 | "storycontext": { 13 | "name": "Fil rouge" 14 | } 15 | }, 16 | "entity": { 17 | "user": { 18 | "fields": { 19 | "nickname": "Totem" 20 | } 21 | } 22 | }, 23 | "global": { 24 | "language": "Français (Scout)" 25 | }, 26 | "views": { 27 | "camp": { 28 | "story": { 29 | "title": "Fil rouge" 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /frontend/src/test/util.js: -------------------------------------------------------------------------------- 1 | export function touch(element) { 2 | const createTrigger = (eventName) => (clientX, clientY) => { 3 | const touches = [{ clientX, clientY }] 4 | const event = new Event(eventName) 5 | 6 | event.touches = touches 7 | event.changedTouches = touches 8 | element.element.dispatchEvent(event) 9 | 10 | return touch(element) 11 | } 12 | 13 | return { 14 | start: createTrigger('touchstart'), 15 | move: createTrigger('touchmove'), 16 | end: createTrigger('touchend'), 17 | } 18 | } 19 | 20 | export const waitForDebounce = () => new Promise((resolve) => setTimeout(resolve, 110)) 21 | -------------------------------------------------------------------------------- /pdf/src/campPrint/tableOfContents/entry/Cover.vue: -------------------------------------------------------------------------------- 1 | 7 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /pdf/src/campPrint/tableOfContents/entry/SafetyConsiderations.vue: -------------------------------------------------------------------------------- 1 | 7 | 17 | -------------------------------------------------------------------------------- /api/templates/emails/button.twig: -------------------------------------------------------------------------------- 1 | {% block button %} 2 | 3 | 4 | 5 | 14 | 15 | 16 | 17 | {% endblock %} -------------------------------------------------------------------------------- /api/tests/Api/Days/UpdateDayTest.php: -------------------------------------------------------------------------------- 1 | request('PATCH', '/days/'.$day->getId(), ['json' => [ 14 | 'dayOffset' => 3, 15 | ], 'headers' => ['Content-Type' => 'application/merge-patch+json']]); 16 | 17 | $this->assertResponseStatusCodeSame(405); // method not allowed 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /api/tests/Api/Invitations/DeleteInvitationTest.php: -------------------------------------------------------------------------------- 1 | request('DELETE', '/invitations/'.$invitation->inviteKey); 16 | 17 | $this->assertResponseStatusCodeSame(404); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /frontend/src/components/buttons/ButtonBack.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /frontend/src/views/CampCreate.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 26 | -------------------------------------------------------------------------------- /api/migrations/dev-data/Version202202051218.php: -------------------------------------------------------------------------------- 1 | message = $message ?? $this->message; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /api/templates/emails/userActivation.de.html.twig: -------------------------------------------------------------------------------- 1 | {% set preheader = 'Willkommen bei eCamp v3' %} 2 | {% extends 'emails/baseLayout.twig' %} 3 | 4 | {% block content %} 5 |

Willkommen bei eCamp v3

6 |

Hallo {{ name }},

7 |

8 | Du hast dich soeben für eCamp registriert.
9 | Bestätige deine Mail-Adresse indem du den nachfolgenden Link öffnest: 10 |

11 | 12 | {% with { title: 'Bestätigen', url: url } %} 13 | {% include 'emails/button.twig' %} 14 | {% endwith %} 15 | 16 |

17 | Beste Grüsse,
18 | dein eCamp-Team 19 |

20 | {% endblock %} 21 | -------------------------------------------------------------------------------- /.helm/ecamp3/templates/api_service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "api.name" . }} 5 | labels: 6 | {{- include "api.selectorLabels" . | nindent 4 }} 7 | {{- include "app.commonLabels" . | nindent 4 }} 8 | spec: 9 | type: {{ .Values.api.service.type }} 10 | ports: 11 | - port: {{ .Values.api.service.port }} 12 | targetPort: api-http 13 | protocol: TCP 14 | name: api-http 15 | - port: {{ .Values.api.metrics.port }} 16 | targetPort: api-metrics 17 | protocol: TCP 18 | name: api-metrics 19 | selector: 20 | {{- include "api.selectorLabels" . | nindent 4 }} 21 | -------------------------------------------------------------------------------- /api/migrations/dev-data/Version202209110752PM.php: -------------------------------------------------------------------------------- 1 | id; 21 | } 22 | 23 | public function setId(string $id): void { 24 | $this->id = $id; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /api/tests/HttpCache/Entity/RelatedDummy.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | #[ORM\Entity] 17 | class RelatedDummy extends BaseEntity { 18 | #[ORM\OneToMany(targetEntity: Dummy::class)] 19 | public Collection|iterable $dummies; 20 | 21 | public function __construct() { 22 | $this->dummies = new ArrayCollection(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /frontend/src/views/auth/LoginCallback.vue: -------------------------------------------------------------------------------- 1 | 14 | 22 | 23 | -------------------------------------------------------------------------------- /.helm/ecamp3/templates/api_cache_vcl_configmap.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.apiCache.enabled }} 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: {{ include "apiCache.name" . }}-vcl-configmap 6 | labels: 7 | {{- include "apiCache.selectorLabels" . | nindent 4 }} 8 | {{- include "app.commonLabels" . | nindent 4 }} 9 | data: 10 | # includes all files except the ones starting with _ 11 | {{ (.Files.Glob "files/vcl/[!_]*").AsConfig | indent 2 }} 12 | # override backend config 13 | _config.vcl: |- 14 | backend default { 15 | .host = "{{ include "api.name" .}}"; 16 | .port = "{{ .Values.api.service.port }}"; 17 | } 18 | {{- end }} -------------------------------------------------------------------------------- /.helm/ecamp3/templates/basic_auth_secret.yml: -------------------------------------------------------------------------------- 1 | {{- if .Values.ingress.basicAuth.enabled -}} 2 | {{- $basicAuth := .Values.ingress.basicAuth -}} 3 | {{- $username := $basicAuth.username | required ".Values.ingress.basicAuth.username is required if .Values.ingress.basicAuth.enabled is true" -}} 4 | {{- $password := $basicAuth.password | required ".Values.ingress.basicAuth.password is required if .Values.ingress.basicAuth.enabled is true" -}} 5 | apiVersion: v1 6 | kind: Secret 7 | metadata: 8 | name: {{ include "ingress.basicAuth.secret.name" . | quote }} 9 | type: Opaque 10 | data: 11 | auth: {{ htpasswd $username $password | b64enc | quote }} 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /api/src/Entity/CampRootContentNode.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{ $tc('print.activityList.title') }} 4 | 5 | 6 | 7 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /api/tests/Api/ContentNodes/MaterialNode/CreateMaterialNodeTest.php: -------------------------------------------------------------------------------- 1 | endpoint = '/content_node/material_nodes'; 17 | $this->entityClass = MaterialNode::class; 18 | $this->defaultContentType = static::getFixture('contentTypeMaterial'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /api/translations/validators.en.yml: -------------------------------------------------------------------------------- 1 | Cannot delete the last entry.: "Cannot delete the last entry." 2 | Cannot delete the last schedule entry.: "Cannot delete the last schedule entry." 3 | Either this value or {{ other }} should not be null.: "Either this value or {{ other }} should not be null." 4 | This inviteEmail is already present in the camp.: "This inviteEmail is already present in the camp." 5 | This is a test message for i18n variants: "en" 6 | This user is already present in the camp.: "This user or a user with this email address is already participating in the camp." 7 | value must be one of {{ to }}, was {{ value }}: "value must be one of {{ to }}, was {{ value }}" 8 | -------------------------------------------------------------------------------- /common/helpers/dayjs/__tests__/formatDatePeriod.spec.js: -------------------------------------------------------------------------------- 1 | import { describe, beforeEach, expect, it } from 'vitest' 2 | import dayjs from '@/common/helpers/dayjs.js' 3 | 4 | describe('formatDatePeriod dayjs plugin', () => { 5 | beforeEach(() => { 6 | dayjs.locale('de') 7 | }) 8 | 9 | it.each([ 10 | ['', ''], 11 | [null, ''], 12 | [undefined, ''], 13 | ['L', '03.04.2023 - 07.04.2023'], 14 | ])('maps %p to %p', (input, expected) => { 15 | const startDate = dayjs('2023-04-03 0:00') 16 | const endDate = dayjs('2023-04-07 0:00') 17 | expect(dayjs.formatDatePeriod(startDate, endDate, input, 'de')).toEqual(expected) 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /frontend/src/components/generic/GenericPage.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 27 | -------------------------------------------------------------------------------- /api/migrations/dev-data/Version202409282339.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 16 | 17 | .toc-dotted-line { 18 | border-bottom: 1px dotted black; 19 | flex-grow: 1; 20 | margin-left: 6pt; 21 | } 22 | .toc-entry-page-number { 23 | width: 24pt; 24 | text-align: right; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /api/migrations/dev-data/Version202409282323.php: -------------------------------------------------------------------------------- 1 | { 5 | it.each([ 6 | [{ id: 'fffffff', profile: () => ({ _meta: {} }) }, ''], 7 | [{ profile: () => ({ legalName: 'test', _meta: {} }) }, 'test'], 8 | [{ profile: () => ({ legalName: 'test', _meta: {} }), _meta: {} }, 'test'], 9 | [{ profile: () => ({ _meta: {} }), _meta: { loading: true } }, ''], 10 | [{ profile: () => ({ _meta: { loading: true } }) }, ''], 11 | ])('maps %p to %p', (input, expected) => { 12 | expect(userLegalName(input)).toEqual(expected) 13 | }) 14 | }) 15 | -------------------------------------------------------------------------------- /wait-for-container-startup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo "Waiting for API container to start up and migrate DB..." 4 | until curl --output /dev/null --silent --fail http://localhost:3000/api 5 | do 6 | sleep 2 7 | done 8 | echo "API container is ready." 9 | 10 | echo "Waiting for print container to start up..." 11 | until curl --output /dev/null --silent --fail http://localhost:3000/print/health 12 | do 13 | sleep 2 14 | done 15 | echo "Frontend container is ready." 16 | 17 | echo "Waiting for frontend container to start up..." 18 | until curl --output /dev/null --silent --fail http://localhost:3000 19 | do 20 | sleep 2 21 | done 22 | echo "Frontend container is ready." 23 | -------------------------------------------------------------------------------- /api/.dockerignore: -------------------------------------------------------------------------------- 1 | **/*.log 2 | **/*.md 3 | **/*.php~ 4 | **/*.dist.php 5 | **/*.dist 6 | **/*.cache 7 | **/._* 8 | **/.dockerignore 9 | **/.DS_Store 10 | **/.git/ 11 | **/.gitattributes 12 | **/.gitignore 13 | **/.gitmodules 14 | **/compose.*.yaml 15 | **/compose.*.yml 16 | **/compose.yaml 17 | **/compose.yml 18 | **/docker-compose.*.yaml 19 | **/docker-compose.*.yml 20 | **/docker-compose.yaml 21 | **/docker-compose.yml 22 | **/Dockerfile 23 | **/Thumbs.db 24 | .editorconfig 25 | .env.*.local 26 | .env.local 27 | .env.local.php 28 | .env.test 29 | .php_cs.cache 30 | bin/* 31 | !bin/console 32 | build/ 33 | docker/db/data/ 34 | helm/ 35 | public/bundles/ 36 | tests/ 37 | var/ 38 | vendor/ 39 | -------------------------------------------------------------------------------- /api/migrations/dev-data/Version202406211251.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 28 | -------------------------------------------------------------------------------- /frontend/src/components/navigation/Logo.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 21 | 22 | 27 | --------------------------------------------------------------------------------