├── .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 |
--------------------------------------------------------------------------------
/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 |
2 |
3 | {{ $tc('global.button.cancel') }}
4 |
5 |
6 |
7 |
12 |
--------------------------------------------------------------------------------
/frontend/src/components/buttons/ButtonContinue.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ $tc('global.button.continue') }}
4 |
5 |
6 |
7 |
12 |
--------------------------------------------------------------------------------
/print/components/scheduleEntry/contentNode/NotImplemented.vue:
--------------------------------------------------------------------------------
1 |
2 | Not implemented: {{ contentNode.contentType().name }}
3 |
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 |
2 |
3 |
4 |
5 |
6 |
7 |
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 |
4 |
--------------------------------------------------------------------------------
/frontend/src/components/buttons/ButtonRetry.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | mdi-refresh
4 | {{ $tc('global.button.tryagain') }}
5 |
6 |
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 |
2 |
3 |
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 |
2 |
3 |
4 |
5 |
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 |
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 |
2 |
3 | {{ icon }}
4 |
5 |
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 |
2 |
3 |
4 |
5 |
22 |
--------------------------------------------------------------------------------
/pdf/src/campPrint/tableOfContents/entry/Summary.vue:
--------------------------------------------------------------------------------
1 |
18 |
--------------------------------------------------------------------------------
/common/assets/logos/JSLogo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/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 |
2 |
3 |
4 |
5 |
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 |
2 |
3 |
6 |
7 |
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 |
2 |
3 |
6 |
7 |
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 |
2 |
3 |
4 |
5 |
21 |
--------------------------------------------------------------------------------
/frontend/src/views/admin/Checklists.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
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 |
7 |
14 |
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 |
2 |
3 |
9 |
10 |
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 |
2 |
3 |
4 | mdi-printer
5 |
6 | {{ $tc('components.print.printNuxt.downloadNuxtPdfButton.label') }}
7 |
8 |
9 |
10 |
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 |
2 |
3 |
4 |
5 |
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 |
2 |
3 |
9 |
10 |
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 |
2 |
3 |
4 |
5 |
6 |
7 |
16 |
17 |
26 |
--------------------------------------------------------------------------------
/frontend/src/components/layout/TextAlignBaseline.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
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 |
2 |
3 |
4 |
5 |
6 |
7 |
25 |
--------------------------------------------------------------------------------
/pdf/src/campPrint/tableOfContents/entry/Story.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ $tc('print.story.title') }}: {{ period.description }}
4 |
5 |
6 |
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 |
8 |
--------------------------------------------------------------------------------
/frontend/src/components/dashboard/BooleanFilter.vue:
--------------------------------------------------------------------------------
1 |
2 | {{ label }}
5 |
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 |
2 |
6 |
7 |
8 |
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 |
2 |
3 | {{ $tc('print.toc.title') }}
4 |
5 |
6 |
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 |
2 |
3 | {{ $tc('print.cover.title') }}
4 |
5 |
6 |
7 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/pdf/src/campPrint/tableOfContents/entry/SafetyConsiderations.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ $tc('print.safetyConsiderations.title') }}: {{ period.description }}
4 |
5 |
6 |
7 |
17 |
--------------------------------------------------------------------------------
/api/templates/emails/button.twig:
--------------------------------------------------------------------------------
1 | {% block button %}
2 |
3 |
4 |
5 | |
6 |
13 | |
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 |
2 |
8 | mdi-arrow-left
9 |
10 | {{ $tc('global.button.back') }}
11 |
12 |
13 |
14 |
15 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/frontend/src/views/CampCreate.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
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 |
2 |
3 |
4 |
5 |
6 |
7 | {{$tc('views.auth.loginCallback.loginInProgress')
8 |
9 |
10 |
11 |
12 |
13 |
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 |
2 |
3 |
4 |
5 |
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 |
2 |
3 |
4 |
5 | $vuetify.icons.ecampeCamp
7 |
8 |
9 |
10 |
11 |
12 |
13 |
21 |
22 |
27 |
--------------------------------------------------------------------------------