Compare commits

...
Author SHA1 Message Date
Rainer Killinger 991fab373c refactor: update elasticsearch to 8.19 2026-10-20 16:13:03 +02:00
Jovan Krunić 3547ad19f6 fix: news settings filter 2026-10-20 15:43:40 +02:00
Jovan Krunić d5fbd8654c feat: app now requests backend version 4.1.0 2026-10-20 15:24:11 +02:00
Jovan Krunić c9ada93f87 fix: remove expired label from the id cards 2026-10-19 17:33:15 +02:00
Jovan Krunić 6d782ecb10 fix: don't use token param for assessments in prod 2026-10-19 16:18:28 +02:00
Jovan Krunić 1cc3ffedf8 fix: remove assessments cache immediately on user change
Closes #256
2026-10-19 15:59:09 +02:00
Rainer Killinger 05a0525320 refactor: update app licenses mentions 2026-10-19 15:40:11 +02:00
Rainer Killinger 3c08704345 ci: fix publish docs job 2026-10-19 12:54:54 +02:00
Jovan Krunić 6b17416d61 docs: update changelogs for release
ci: publish release
2026-10-19 10:43:27 +02:00
Jovan Krunić 019f80134d refactor: update changesets 2026-10-19 10:40:26 +02:00
Jovan Krunić ba728d551b feat: use only one identity provider
Additionally remove ionic-appauth dependency,
refactor the relevant code and fix some issues.

Closes #245
2026-10-18 16:10:13 +02:00
Jovan Krunić c6dfbd6add fix: use same width as other about pages 2026-10-13 16:12:25 +02:00
Jovan Krunić 27877c6607 fix: flickering in chrome when switching views
Related to #253
2026-10-13 11:57:46 +02:00
Jovan Krunić f552586b50 fix: show calendar label using a proper soft hyphen
Closes #254
2026-10-12 10:36:03 +02:00
Rainer Killinger 4c3f3ef14c fix: app resources:ios script 2026-10-09 16:16:53 +02:00
Rainer Killinger 4c5d529589 docs: update changelogs for release
ci: publish release
2026-10-09 14:13:12 +02:00
Rainer Killinger 09ad903a30 refactor: update changesets 2026-10-09 13:48:01 +02:00
Rainer Killinger a482f0bf0b refactor: update capactior and native sdk projects 2026-10-09 13:48:01 +02:00
Jovan KrunićandRainer Killinger da81e06bc2 fix: flickering in chrome when switching views
Closes #253
2026-10-09 13:48:00 +02:00
Rainer Killinger 3efd5d4b31 fix: bump critical peer dependencies 2026-10-09 13:48:00 +02:00
Jovan KrunićandRainer Killinger 3ee036c85e fix: blurred news image background detail in firefox 2026-10-09 13:48:00 +02:00
Jovan KrunićandRainer Killinger 8cec8bacbe fix: properly show places on the map in detail view
Closes #252
2026-10-09 13:48:00 +02:00
Jovan KrunićandRainer Killinger 790b10e57b fix: show 3d buildings only when the map is tilted 2026-10-09 13:48:00 +02:00
Rainer Killinger 2a5c8724b1 ci: update app-builder image 2026-10-09 13:47:59 +02:00
Jovan KrunićandRainer Killinger 4b145f3b2f fix: make gelocation work reliably
Closes #249
2026-10-09 13:47:59 +02:00
Jovan KrunićandRainer Killinger 2438873fd0 fix: translate service injection
Closes #250
2026-10-09 13:47:59 +02:00
Jovan KrunićandRainer Killinger fbb42042bf fix: replace deprecated sass import with use rules 2026-10-09 13:47:59 +02:00
Rainer Killinger 209469c6a7 refactor: fix map controlls 2026-10-09 13:47:59 +02:00
Rainer Killinger 736950e064 refactor: id-cards related test 2026-10-09 13:47:59 +02:00
Rainer Killinger 090ec17ccb refactor: upgrade typescript-eslint and start the stylistic migration 2026-10-09 13:47:58 +02:00
Rainer Killinger 66ae7a39a1 refactor: upgrade project to Typescript 5.9 2026-10-09 13:47:58 +02:00
Rainer Killinger 58b4822265 refactor: apply Angular 20 inject rules 2026-10-09 13:47:58 +02:00
Rainer Killinger 9026c88fac refactor: angular 20 upgrade 2026-10-09 13:47:58 +02:00
Rainer Killinger 1f7b010dc9 refactor: maplibre update 2026-10-09 13:47:57 +02:00
Rainer Killinger 01c9b63eb9 refactor: fix new Angular warnings 2026-10-09 13:47:57 +02:00
Rainer Killinger b109100257 refactor: migrate sass/scss deprecations 2026-10-09 13:47:57 +02:00
Rainer Killinger 5f48bca962 fix: update @ionic/angular* and patch dependencies 2026-10-09 13:47:56 +02:00
Rainer Killinger d1709c3353 refactor: update to Angular 19.2 2026-10-09 13:47:56 +02:00
Rainer Killinger 65facc131a refactor: update to typescript 5.5.4 2026-10-09 13:47:56 +02:00
Jovan KrunićandRainer Killinger a1de793993 refactor: open external links without javascript in browser
Close #246
2026-10-09 13:47:56 +02:00
Jovan KrunićandRainer Killinger 592e655990 refactor: remove library features
Closes #244
2026-10-09 13:47:55 +02:00
Rainer Killinger 5d0d2dd136 fix: update critical production dependencies 2026-10-09 13:47:55 +02:00
Rainer Killinger f5582e91fe docs: update changelogs for release
ci: publish release
2026-06-03 16:33:57 +02:00
Rainer Killinger 2c7bed0b8b ci: enable failed audit jobs for main 2026-06-03 16:14:42 +02:00
Rainer Killinger 87d0af5a39 ci: remove edge browser from cypress 2026-06-03 16:14:35 +02:00
Rainer Killinger 8ccbfac0b1 refactor: bump proxy version to rebuild image from latest source 2026-06-03 12:38:50 +02:00
Rainer Killinger 8550bf976b refactor: capacitor 8 upgrade 2026-03-13 13:10:50 +01:00
Rainer Killinger 86004881b0 fix: update node-glob dependency 2026-01-05 10:44:02 +01:00
Rainer Killinger 3d19fc87e3 fix: hot fix for android 35 edge to edge window rendering 2025-08-28 13:05:52 +02:00
Rainer Killinger 80bcdad851 refactor: update app licenses file 2025-08-27 13:49:57 +02:00
Rainer Killinger afd1c8d87e docs: update changelogs for release
ci: publish release
2025-08-27 13:00:27 +02:00
Rainer Killinger 6941f83b8f refactor: complete changeset 2025-08-27 12:02:10 +02:00
Rainer Killinger 3a274a3a7f refactor: upgrade to Capacitor 7 & Angular 18 2025-08-27 11:27:11 +02:00
Rainer Killinger 5a48342a8d docs: update changelogs for release
ci: publish release
2025-07-30 14:15:24 +02:00
Rainer Killinger 6b06de4019 refactor: update audit relevant nodemailer dependency 2025-07-30 13:58:25 +02:00
Rainer Killinger c5c9bcf433 docs: update changelogs for release
ci: publish release
2025-07-30 12:44:30 +02:00
Rainer Killinger b40ba7ad63 refactor: update elasticsearch and audit relevant dependencies 2025-07-30 12:40:59 +02:00
Jovan KrunićandJovan Krunić 362f6adf07 fix: use modal instead of menu inside of a split pane
Closes #234
2025-07-08 14:05:30 +02:00
Rainer Killinger bbd6b0f874 fix: app missing chevron buttons in schedule module 2025-07-02 16:44:23 +02:00
Rainer Killinger b1a9ba44d0 fix: app now requests backend version 4.0.0 2025-07-02 12:04:41 +02:00
Rainer Killinger bee38d4a59 docs: update changelogs for release
ci: publish release
2025-07-01 16:29:42 +02:00
Rainer Killinger a5c5c31d09 fix: app cypress e2e tests failing on core major version change 2025-07-01 15:33:27 +02:00
Rainer Killinger c8e290200f refactor: update to node 22 2025-06-30 16:55:33 +02:00
Rainer Killinger ef4e1f8ded refactor: move ion-menu-button for context menu filtering in ion-toolbar 2025-06-18 15:29:18 +02:00
Rainer Killinger 5759a1cbb1 refactor: update to ionic 8 and update capactior 6 + angular 17 dependencies 2025-06-18 15:29:11 +02:00
TheaninovaandRainer Killinger b8ac30b9d0 refactor: migrate to angular esbuild
refactor: migrate to ionic standalone components
refactor: migrate ion icons to a custom element
2025-06-18 14:19:56 +02:00
Rainer Killinger 436e1471a7 docs: update changelogs for release
ci: publish release
2024-12-02 11:26:24 +01:00
Rainer Killinger 4c9d330c88 fix: update jsonpath-plus depenency 2024-12-02 11:08:58 +01:00
Thea SchöblandJovan Krunić 580ebee362 fix: user gets logged out when their token expires
Closes #230
2024-11-28 18:04:08 +00:00
Rainer Killinger 07e5c80223 docs: update changelogs for release
ci: publish release
2024-11-05 11:40:19 +01:00
Jovan Krunić 2ac840d845 fix: observable immediately returns false if scheduled beyond max delay
Closes #229
2024-11-04 18:04:48 +01:00
Thea SchöblandRainer Killinger 8b581ef9ca feat: rework about pages changelog 2024-11-04 07:50:47 +00:00
Rainer Killinger e2d5d4f187 docs: update changelogs for release
ci: publish release
2024-10-18 16:52:57 +02:00
Rainer Killinger 496b50d892 fix: update jsonpath-plus depenency 2024-10-18 16:12:29 +02:00
Theaninova e6c17c860b fix: id cards are wiped/replaced when an error happens in the pipe 2024-10-11 15:33:03 +02:00
Jovan KrunićandThea Schöbl bb1f596bfc fix: enable starting the app without backend
Closes #223
2024-09-30 11:03:53 +00:00
Theaninova 0c49fd8c34 refactor: update nix dependencies 2024-09-30 13:00:59 +02:00
Thea SchöblandJovan Krunić ce5016a992 fix: text of the feedback form not fully visible
Closes #227
2024-09-18 09:53:50 +00:00
Theaninova 3ac8c04765 fix: date range is now pipe has issues around boundaries 2024-08-06 17:43:59 +02:00
Rainer Killinger 5c260dd26b refactor: update android build dependencies for API level 34 2024-08-05 12:51:47 +00:00
Rainer Killinger f2e1a6ddd5 docs: update changelogs for release
ci: publish release
2024-08-02 10:19:44 +02:00
Rainer Killinger ccacfbf710 fix: publish-packages script 2024-08-02 10:18:57 +02:00
Rainer Killinger b249b329f7 refactor: use development backend for non production environment 2024-08-01 17:44:21 +02:00
Jovan KrunićandRainer Killinger 7afc24f1bc fix: use major version config from storage when offline
Closes #218
2024-08-01 17:44:20 +02:00
Rainer Killinger 7276525dfa fix: app-builder image build due to nodejs versions <18.19 not being supported by angular 17 2024-08-01 15:24:59 +02:00
Jovan Krunić c9e881582f refactor: set production version of the backend 2024-07-19 15:20:06 +02:00
Jovan Krunić df681de083 feat: show title if available on library account profile
Closes #215
2024-07-19 15:20:06 +02:00
TheaninovaandJovan Krunić 802a7a3fa7 fix: docs generation 2024-07-19 15:20:06 +02:00
Jovan Krunić 343d03e647 feat: library account adjustments
Closes #214
2024-07-19 15:20:06 +02:00
TheaninovaandJovan Krunić 727b92911e fix: list item layout broken 2024-07-19 15:20:06 +02:00
TheaninovaandJovan Krunić 11bc987807 fix: elasticsearch integration spams errors 2024-07-19 15:20:06 +02:00
Rainer Killinger b8faae5988 docs: update changelogs for release
ci: publish release
2024-06-28 17:39:39 +02:00
TheaninovaandRainer Killinger 67ab1fd613 fix: geo.point has wrong mapping 2024-06-28 17:25:32 +02:00
Rainer Killinger 142079bf0e refactor: set app backend to dev version 2024-06-28 12:02:59 +02:00
Rainer Killinger 5050ac90eb docs: update changelogs for release
ci: publish release
2024-06-28 09:28:39 +02:00
Rainer Killinger 688bc5f2e7 refactor: add changeset 2024-06-28 09:03:54 +02:00
Rainer Killinger ad174dd7d7 refactor: use static map files from backend 2024-06-28 08:59:08 +02:00
Rainer Killinger 26e654f5b8 fix: app license overview 2024-06-27 14:57:24 +02:00
Rainer Killinger 5439484a90 fix: changelog typo 2024-06-27 12:06:52 +02:00
Rainer Killinger 68f3366a27 refactor: adjustments for recent PAIA changes 2024-06-27 09:23:55 +00:00
Jovan KrunićandThea Schöbl dea9a82105 fix: do not fetch remote configuration if offline
Closes #206
2024-06-17 09:55:29 +00:00
Theaninova 39d2801114 feat: store id cards 2024-06-12 13:51:46 +02:00
Rainer KillingerandThea Schöbl 341b209092 refactor: display id-cards in their own modal 2024-06-05 11:07:30 +00:00
Rainer Killinger a6b88d3534 refactor: add f-u specific changelogs 2024-05-27 16:27:37 +02:00
Rainer Killinger be863daaef refactor: updated used licences within the app 2024-05-27 15:36:00 +02:00
TheaninovaandRainer Killinger 2f64d69693 feat: migrate to protomaps and maplibre 2024-05-27 15:07:27 +02:00
TheaninovaandRainer Killinger 964516d3cf fix: remove noUnused* TSConfig options
TSConfig options prevent Angular from compiling the app. This is
specifically harsh with the noUnused* rules, which require you to
strictly remove any unused variables even in dev mode while testing.
Since this case is already covered by ESLint, the TSConfig option was
removed.
2024-05-27 15:07:27 +02:00
TheaninovaandRainer Killinger 71ff9fd960 fix: favorite button 2024-05-27 15:07:27 +02:00
TheaninovaandRainer Killinger abf9999461 feat: type-safe sc-icons 2024-05-27 15:07:26 +02:00
TheaninovaandRainer Killinger 53c3d0ba0c refactor: replace rfdc with native structuredClone 2024-05-27 15:07:25 +02:00
Rainer Killinger 622481a3c9 docs: update changelogs for release\n\nci: publish release 2024-03-28 14:27:56 +01:00
Thea Schöbl 1ab5c0c355 fix: inPlace in list items is placed weird 2024-03-27 13:45:22 +00:00
Rainer Killinger b0f6ffb21c refactor: ajdust app environment to backend version >= v3.1.0 2024-03-27 10:11:32 +01:00
Rainer Killinger e658cff9d2 refactor: use GET for id-cards requests 2024-03-27 09:55:31 +01:00
Rainer Killinger e71355a2fb fix: malformed Bearer header in id-cards provider 2024-03-27 09:55:30 +01:00
TheaninovaandRainer Killinger 100607740b fix: angular lsp broken 2024-03-27 09:55:30 +01:00
Thea SchöblandRainer Killinger 10c4466b37 feat: update to angular 17 2024-03-27 09:55:30 +01:00
Rainer Killinger 09faa66e98 fix: broken build and test stage 2024-03-27 09:55:30 +01:00
Rainer Killinger 7c5687111f fix: check-icons script in app 2024-03-27 09:55:30 +01:00
Rainer Killinger c066028e49 refactor: update asdf .tool-versions 2024-03-27 09:55:30 +01:00
TheaninovaandRainer Killinger 0858a26dc1 fix: dish prices sometimes go missing 2024-03-27 09:55:30 +01:00
TheaninovaandRainer Killinger 8667603bd6 feat: export core version in package 2024-03-27 09:55:29 +01:00
TheaninovaandRainer Killinger 65bc9a76b6 feat: add syncpack semver ranges 2024-03-27 09:55:29 +01:00
TheaninovaandRainer Killinger 912ae42270 feat: add ability to check for existence of a field 2024-03-27 09:55:29 +01:00
TheaninovaandRainer Killinger c4a5d6e73b fix: exclude app.js and lib from typescript compliation 2024-03-27 09:55:29 +01:00
TheaninovaandRainer Killinger deed376c24 feat: enable checkJs by default 2024-03-27 09:55:29 +01:00
TheaninovaandRainer Killinger a4cc23e9a8 feat: add direnv for nix
feat: update nix flake to not rely on buildFHSUserEnv
2024-03-27 09:55:29 +01:00
TheaninovaandRainer Killinger e8d72683ef fix: backend tests break every year
refactor: update some backend unit tests
2024-03-27 09:55:28 +01:00
Rainer Killinger e3d068f8d4 fix: iOS build resources 2024-03-27 09:55:28 +01:00
Rainer Killinger b346d216a3 refactor: add asdf tool versioning file 2024-03-27 09:55:28 +01:00
TheaninovaandRainer Killinger dbb558508f fix: changeset crashes because it uses internal prettier version 2024-03-27 09:55:28 +01:00
Rainer Killinger 754d99c1b4 refactor: overhaul minimal-deployment compose file 2024-03-27 09:55:27 +01:00
Rainer Killinger 689ac68be3 fix: pin alpine version to 3.18 and add healthchecks 2024-03-06 11:45:40 +01:00
Rainer Killinger d36d9596fc docs: update changelogs for release 2023-12-19 15:32:42 +01:00
Thea SchöblandRainer Killinger 8d50f669e7 feat: collapse detail titles into header bar 2023-12-19 14:16:38 +01:00
Jovan KrunićandRainer Killinger dce08d9c03 fix: reverse workaround after update of capacitor
Closes #179
2023-12-19 13:12:25 +00:00
Rainer Killinger 296054c8e0 docs: update changelogs for release
ci: publish release
2023-12-13 16:42:45 +01:00
Theaninova 859763367e fix: throw error if config import fails
feat: log used config in backend
2023-12-12 14:37:24 +01:00
Rainer Killinger 848fde4660 refactor: increase maxRequestBodySize to 2 MB 2023-12-11 13:00:52 +01:00
Rainer Killinger bd1046a19a docs: update changelogs for release
ci: publish release
2023-12-08 18:03:41 +01:00
Rainer Killinger 3b9068197c fix: pettier config causing changeset to crash 2023-12-08 17:35:00 +01:00
Thea SchöblandRainer Killinger d2c8120255 feat: simplify version history api 2023-12-08 13:49:53 +00:00
Theaninova d44204cf8d fix: remove old console.log statements 2023-12-06 17:15:03 +01:00
Theaninova 9d5dd05bb6 refactor: remove nullish coalecing pipe 2023-12-06 17:15:03 +01:00
Theaninova 288a49113f refactor: migrate to strict template checking 2023-12-06 17:14:55 +01:00
TheaninovaandThea Schöbl 791b5c895d fix: hide navigation from jop posting search 2023-12-05 15:51:57 +00:00
TheaninovaandThea Schöbl d7a85b7fae feat: improved e2e tests 2023-12-05 15:17:00 +00:00
Rainer Killinger bff2d985aa refactor: use latest backend (4.1.0) 2023-12-05 12:06:11 +00:00
Rainer Killinger 655efc9d29 fix: map location preview collapsed in webkit 2023-12-05 12:06:11 +00:00
Rainer KillingerandThea Schöbl 66712bdd24 fix: iOS app not starting 2023-12-05 11:19:46 +00:00
TheaninovaandThea Schöbl 8b5b4c765b fix: my app card layout 2023-12-05 10:36:22 +00:00
Thea Schöbl 31a6ebfd3f feat: upgrade prettier to v3 2023-12-05 10:36:04 +00:00
Rainer Killinger 991ed1cb1f docs: update changelogs for release
ci: publish release
2023-12-01 19:05:06 +01:00
Rainer Killinger 1efe5c1449 refactor: don't open webpack-bundle-analyzer 2023-12-01 18:28:41 +01:00
Rainer Killinger 4dbeb9936c refactor: adjust f-u release version history 2023-12-01 18:19:36 +01:00
Rainer Killinger 29e6128141 fix: resources:ios script not being BSD compatible 2023-12-01 18:15:15 +01:00
871 changed files with 42144 additions and 33459 deletions
+1
View File
@@ -0,0 +1 @@
use flake
+3 -1
View File
@@ -24,6 +24,7 @@ report-junit.xml
# NixOS flake
result
hsperfdata_root
.direnv/
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
@@ -97,7 +98,8 @@ typings/
# ignore ide files
.idea
.vscode
.vscode?*
!.vscode/launch.json
# ignore lib
lib
+8 -23
View File
@@ -21,13 +21,7 @@ include:
- local: /.gitlab/publishing.gitlab-ci.yml
variables:
TURBO_CACHE_BYPASS:
value: ''
options:
- '--force'
- '--no-cache'
- ''
description: Bypass turbo cache
TURBO_CACHE_BYPASS: "--force --no-cache"
default:
image: registry.gitlab.com/openstapps/openstapps/node-builder
@@ -36,10 +30,7 @@ default:
interruptible: true
before_script:
- corepack enable
- corepack prepare pnpm@latest-8 --activate
- echo TURBO_API=$TURBO_API >> .env.local
- echo TURBO_TOKEN=$TURBO_TOKEN >> .env.local
- echo TURBO_TEAM=$TURBO_TEAM >> .env.local
- corepack prepare pnpm@latest-10 --activate
- pnpm config set store-dir .pnpm-store
cache: &pnpm_cache
key:
@@ -63,13 +54,13 @@ build:
# - pnpm i --prefer-offline
# - pnpm build:full:skip || pnpm i -r --prefer-offline
- pnpm install
# TODO: whats the benifit for CI? something doesn't work with git here...
# TODO: whats the benefit for CI? something doesn't work with git here...
# "🦋 error Error: Failed to find where HEAD diverged from master. Does master exist?"
# - pnpm changeset:status
- pnpm build:full $TURBO_CACHE_BYPASS
- .gitlab/ci/enableGitlabReviewToolbar.sh frontend/app/www/index.html "$CI_PROJECT_ID" "$CI_OPEN_MERGE_REQUESTS"
- cp frontend/app/www/index.html frontend/app/www/200.html
- pnpm dlx surge -p frontend/app/www -d https://$CI_PROJECT_NAME-$DEPLOY_ID.surge.sh/
- .gitlab/ci/enableGitlabReviewToolbar.sh frontend/app/www/browser/index.html "$CI_PROJECT_ID" "$CI_OPEN_MERGE_REQUESTS"
- cp frontend/app/www/browser/index.html frontend/app/www/browser/200.html
- pnpm dlx surge -p frontend/app/www/browser -d https://$CI_PROJECT_NAME-$DEPLOY_ID.surge.sh/
cache:
<<: *pnpm_cache
policy: pull-push
@@ -105,13 +96,7 @@ unit:
stage: test
needs: ['build']
script:
# - pnpm config set recursive-install false
# - pnpm i --prefer-offline
# - pnpm test:skip || pnpm i -r --prefer-offline
- pnpm install
- cd node_modules/.pnpm/re2*/node_modules/re2
- npm run install
- cd $CI_PROJECT_DIR
- pnpm test $TURBO_CACHE_BYPASS
coverage: '/Statements[^:]*\:[^:]*\s+([\d\.]+)%/'
artifacts:
@@ -135,6 +120,6 @@ audit:
script:
- pnpm audit --prod --audit-level critical
rules:
- if: $CI_COMMIT_BRANCH == 'main'
allow_failure: false
- !reference [.limit_pipelines, rules]
# - if: $CI_COMMIT_BRANCH == 'main'
# allow_failure: false
+1 -1
View File
@@ -27,7 +27,7 @@ publish image:
- tags
needs: ['deploy']
image:
name: gcr.io/kaniko-project/executor:v1.12.1-debug
name: gcr.io/kaniko-project/executor:v1.24.0-debug
entrypoint: [""]
script:
- >
+1
View File
@@ -0,0 +1 @@
pnpm-lock.yaml
+9 -2
View File
@@ -2,7 +2,13 @@
/** @type {import('syncpack').RcFile} */
const config = {
semverRange: '',
semverGroups: [
{
range: '',
dependencies: ['**'],
packages: ['**'],
}
],
source: ['package.json', '**/package.json'],
indent: ' ',
sortFirst: [
@@ -21,6 +27,7 @@ const config = {
'bin',
'files',
'engines',
'packageManager',
'scripts',
'dependencies',
'devDependencies',
@@ -49,7 +56,7 @@ const config = {
{
label: 'Packages should use workspace version',
dependencies: ['@openstapps/**'],
dependencyTypes: ['prod', 'dev'],
dependencyTypes: ['prod', 'dev', 'peer'],
packages: ['**'],
pinVersion: 'workspace:*',
},
+3
View File
@@ -0,0 +1,3 @@
nodejs 22.16.0
pnpm 10.12.3
python 3.11.5
+23
View File
@@ -0,0 +1,23 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch Chrome",
"request": "launch",
"type": "chrome",
"url": "http://localhost:8100",
"webRoot": "${workspaceFolder}/frontend/app/www"
},
{
"type":"node",
"request": "launch",
"name": "Run mocha for nodejs workspace",
"runtimeExecutable": "${fileDirname}/../node_modules/.bin/c8",
"cwd": "${fileDirname}/../",
"runtimeArgs": ["--config", "${workspaceFolder}/.c8rc.json", "${fileDirname}/../node_modules/.bin/mocha", "--exit", "--reporter", "spec"]
},
]
}
+2 -2
View File
@@ -9,8 +9,8 @@ integration:
- name: registry.gitlab.com/openstapps/openstapps/database:latest
alias: elasticsearch
script:
- pnpm --filter=@openstapps/backend install
- pnpm test:integration:backend
- pnpm install
- pnpm test:integration:backend --force --no-cache
artifacts:
when: on_failure
paths:
+110
View File
@@ -1,5 +1,115 @@
# @openstapps/backend
## 4.0.6
### Patch Changes
- 019f8013: Enable ID cards and assessments using Shibboleth as identity provider
## 4.0.5
### Patch Changes
- Updated dependencies [86004881]
- Updated dependencies [09ad903a]
- @openstapps/core-tools@4.0.5
- @openstapps/core@4.0.5
## 4.0.3
### Patch Changes
- 3a274a3a: Upgrade to Capacitor 7 and Anuglar 18
- @openstapps/core@4.0.2
- @openstapps/core-tools@4.0.2
- @openstapps/logger@4.0.2
## 4.0.2
### Patch Changes
- 6b06de40: Updated nodemailer dependency
- Updated dependencies [6b06de40]
- @openstapps/logger@4.0.2
- @openstapps/core@4.0.2
- @openstapps/core-tools@4.0.2
## 4.0.1
### Patch Changes
- b40ba7ad: Updated Elasticsearch dependency
- @openstapps/core@4.0.0
## 4.0.0
### Major Changes
- c8e29020: Update to Node 22
### Patch Changes
- Updated dependencies [c8e29020]
- @openstapps/core@4.0.0
- @openstapps/core-tools@4.0.0
- @openstapps/logger@4.0.0
## 3.3.2
### Patch Changes
- @openstapps/core@3.3.2
- @openstapps/core-tools@3.3.2
## 3.3.1
### Patch Changes
- 67ab1fd6: fix for geo.point mapping
## 3.3.0
### Minor Changes
- 688bc5f2: v3.3.0 changes
### Patch Changes
- Updated dependencies [688bc5f2]
- @openstapps/core@3.3.0
- @openstapps/core-tools@3.3.0
- @openstapps/logger@3.0.0
## 3.2.0
### Minor Changes
- 912ae422: Add the ability to filter by existence of a field
### Patch Changes
- 689ac68b: pin alpine version to 3.18 and add healthchecks
- e8d72683: Backend unit tests break every year
- Updated dependencies [912ae422]
- @openstapps/core@4.0.0
- @openstapps/core-tools@3.0.0
- @openstapps/logger@3.0.0
## 3.1.2
### Patch Changes
- Fix backend rejecting plugins
- Fix backend sliently falling back to default configs
## 3.1.1
### Patch Changes
- Fix version history offered by backend
- Updated dependencies
- @openstapps/core@3.1.1
## 3.1.0
### Minor Changes
+2
View File
@@ -9,4 +9,6 @@ ENV NODE_ENV=production
WORKDIR /app
EXPOSE 3000
HEALTHCHECK --interval=10s --timeout=10s --start-period=10s --retries=12 CMD curl -s --fail --request POST --data '{}' --header 'Content-Type: application/json' http://localhost:3000/ >/dev/null || exit 1
ENTRYPOINT ["node", "app.js"]
@@ -1,5 +1,3 @@
// @ts-check
/**
* This is the database configuration for the technical university of berlin
*
@@ -1,4 +1,3 @@
// @ts-check
import {SCSettingInputType, SCThingOriginType, SCThingType} from '@openstapps/core';
/** @type {import('@openstapps/core').SCLanguageSetting} */
+1 -29
View File
@@ -1,4 +1,3 @@
// @ts-check
/** @type {import('@openstapps/core').SCAppConfigurationMenuCategory[]} */
const menus = [
{
@@ -30,19 +29,6 @@ const menus = [
},
},
},
{
icon: 'local_library',
route: '/hebis-search',
title: 'library catalog',
translations: {
de: {
title: 'Bibliothekskatalog',
},
en: {
title: 'library catalog',
},
},
},
{
icon: 'inventory_2',
route: '/catalog',
@@ -113,7 +99,7 @@ const menus = [
icon: 'school',
items: [
{
icon: 'grade',
icon: 'star',
route: '/favorites',
title: 'favorites',
translations: {
@@ -138,20 +124,6 @@ const menus = [
},
},
},
{
authProvider: 'paia',
icon: 'badge',
route: '/library-account',
title: 'library account',
translations: {
de: {
title: 'Bibliothekskonto',
},
en: {
title: 'library account',
},
},
},
{
icon: 'settings',
route: '/settings',
@@ -1,4 +1,3 @@
// @ts-check
import {SCSettingInputType, SCThingOriginType, SCThingType} from '@openstapps/core';
/** @type {import('@openstapps/core').SCUserGroupSetting} */
@@ -6,8 +5,8 @@ const userGroupSetting = {
categories: ['profile'],
defaultValue: 'students',
description:
'The user group the app is going to be used.' +
'This settings for example is getting used for the predefined price category of mensa meals.',
'The user group the app is going to use primarily.' +
' This settings for example is getting used for the predefined price category of mensa meals.',
inputType: SCSettingInputType.SingleChoice,
name: 'group',
order: 1,
@@ -26,7 +25,7 @@ const userGroupSetting = {
},
en: {
description:
'The user group the app is going to be used.' +
'The user group the app is going to use primarily.' +
' This settings for example is getting used for the predefined price category of mensa meals.',
name: 'Group',
values: ['students', 'employees', 'guests'],
@@ -1,4 +1,3 @@
// @ts-check
import {SCThingType} from '@openstapps/core';
/** @type {import('@openstapps/core').SCBackendAggregationConfiguration[]} */
@@ -1,4 +1,3 @@
// @ts-check
import {
month,
sommerRange,
@@ -1,4 +1,3 @@
// @ts-check
import {SCThingType} from '@openstapps/core';
import aggregations from './aggregations.js';
import boostings from './boostings.js';
@@ -17,7 +16,7 @@ export const backend = {
hiddenTypes: [SCThingType.DateSeries, SCThingType.Diff, SCThingType.Floor],
mappingIgnoredTags: ['minlength', 'pattern', 'see', 'tjs-format'],
maxMultiSearchRouteQueries: 5,
maxRequestBodySize: 512 * 1024,
maxRequestBodySize: 2e6,
name: 'Goethe-Universität Frankfurt am Main',
namespace: '909a8cbc-8520-456c-b474-ef1525f14209',
sortableFields: [
@@ -1,4 +1,3 @@
// @ts-check
import app from './app/index.js';
import {backend, internal} from './backend/index.js';
@@ -1,5 +1,3 @@
// @ts-check
/**
* This is the default configuration for elasticsearch (a database)
*
@@ -11,13 +9,13 @@
*
* To get more information about the meaning of specific fields, please use your IDE to read the TSDoc documentation.
*
* @type {import('../../src/storage/elasticsearch/types/elasticsearch-config.js')}
* @type {import('../../src/storage/elasticsearch/types/elasticsearch-config.js').ElasticsearchConfigFile}
*/
const config = {
internal: {
database: {
name: 'elasticsearch',
version: '5.6',
version: '8.4.2',
query: {
minMatch: '75%',
queryType: 'dis_max',
@@ -1,4 +1,3 @@
// @ts-check
import {readFile} from 'fs/promises';
import {SCAboutPageContentType} from '@openstapps/core';
@@ -1,4 +1,3 @@
// @ts-check
/**
* Generates a range of numbers that represent consecutive calendar months
*
+10 -15
View File
@@ -1,5 +1,6 @@
// @ts-check
import {readFile} from 'fs/promises';
import {readFile, readdir} from 'fs/promises';
import url from 'url';
import path from 'path';
/**
* @example version(1, import.meta.url)
@@ -23,20 +24,14 @@ export async function version(options, base) {
}
/**
* @param infos {Record<string, import('@openstapps/core').SCAppVersionInfo['published']>}
* @param base {string} Base path of the file as `import.meta.url`
* @returns {Promise<import('@openstapps/core').SCAppVersionInfo[]>}
*/
export async function versions(infos, base) {
return Promise.all(
Object.entries(infos).map(([versionName, published]) =>
version(
{
published,
version: versionName,
},
base,
),
),
).then(it => it.sort(({version: a}, {version: b}) => -a.localeCompare(b, undefined, {numeric: true})));
export async function versions(base) {
const directory = await readdir(path.dirname(url.fileURLToPath(base)));
const versions = [
...new Set(directory.filter(it => it.endsWith('.md')).map(it => it.replace(/\.\w+\.md$/, ''))),
].sort((a, b) => -a.localeCompare(b, undefined, {numeric: true}));
return Promise.all(versions.map(versionName => version({version: versionName}, base)));
}
@@ -1,4 +1,3 @@
// @ts-check
import {SCAboutPageContentType} from '@openstapps/core';
import {markdown} from '../../default/tools/markdown.js';
@@ -1,4 +1,3 @@
// @ts-check
import {SCAboutPageContentType} from '@openstapps/core';
/** @type {import('@openstapps/core').SCAboutPage} */
@@ -1,4 +1,3 @@
// @ts-check
import about from './about.js';
import imprint from './imprint.js';
import privacy from './privacy.js';
@@ -1,4 +1,3 @@
// @ts-check
import {markdown} from '../../default/tools/markdown.js';
/** @type {import('@openstapps/core').SCAboutPage} */
+17 -46
View File
@@ -1,4 +1,3 @@
// @ts-check
import aboutPages from './about-pages/index.js';
import defaultApp from '../default/app/index.js';
import {backend as defaultBackend, internal as defaultInternal} from '../default/backend/index.js';
@@ -14,42 +13,24 @@ const config = {
default: {
client: {
clientId: '1cac3f99-33fa-4234-8438-979f07e0cdab',
scopes: '',
url: 'https://cas.rz.uni-frankfurt.de/cas/oauth2.0',
scopes: 'openid profile email offline_access',
url: 'https://idp.ub.uni-frankfurt.de/idp/profile/oidc',
},
endpoints: {
authorization: 'https://cas.rz.uni-frankfurt.de/cas/oauth2.0/authorize',
endSession: 'https://cas.rz.uni-frankfurt.de/cas/logout',
authorization: 'https://idp.ub.uni-frankfurt.de/idp/profile/oidc/authorize',
endSession: 'https://idp.ub.uni-frankfurt.de/idp/profile/oidc/end-session',
mapping: {
id: '$.id',
email: '$.attributes.mailPrimaryAddress',
familyName: '$.attributes.sn',
givenName: '$.attributes.givenName',
name: '$.attributes.givenName',
role: '$.attributes.eduPersonPrimaryAffiliation',
studentId: '$.attributes.employeeNumber',
},
token: 'https://cas.rz.uni-frankfurt.de/cas/oauth2.0/accessToken',
userinfo: 'https://cas.rz.uni-frankfurt.de/cas/oauth2.0/profile',
},
},
paia: {
client: {
clientId: '',
scopes: '',
url: 'https://hds.hebis.de/Shibboleth.sso/UBFFM?target=https://hds.hebis.de/ubffm/paia_login_stub.php',
},
endpoints: {
authorization:
'https://hds.hebis.de/Shibboleth.sso/UBFFM?target=https://hds.hebis.de/ubffm/paia_login_stub.php',
endSession: 'https://ubffm.hds.hebis.de/Shibboleth.sso/Logout',
mapping: {
id: '$.email',
id: '$.preferred_username',
email: '$.mailPrimaryAddress',
familyName: '$.family_name',
givenName: '$.given_name',
name: '$.name',
role: '$.type',
role: '$.eduPersonPrimaryAffiliation',
studentId: '$.employeeNumber',
},
token: 'https://hds.hebis.de/paia/auth/login',
userinfo: 'https://hds.hebis.de/paia/core',
token: 'https://idp.ub.uni-frankfurt.de/idp/profile/oidc/token',
userinfo: 'https://idp.ub.uni-frankfurt.de/idp/profile/oidc/userinfo',
revoke: 'https://idp.ub.uni-frankfurt.de/idp/profile/oauth2/revocation',
},
},
},
@@ -59,22 +40,12 @@ const config = {
extern: {
hisometry: {
authProvider: 'default',
url: 'https://his-self-service.rz.uni-frankfurt.de',
url: 'https://his-self-service.rz.uni-frankfurt.de/v2',
},
daia: {
url: 'https://daia.hebis.de/DAIA2/UB_Frankfurt',
},
hebisProxy: {
url: 'https://proxy.ub.uni-frankfurt.de/login?qurl=',
},
paia: {
authProvider: 'paia',
url: 'https://hds.hebis.de/paia/core',
},
/** TODO: idCards: {
idCards: {
authProvider: 'default',
url: 'TODO',
} */
url: 'https://id-cards.rz.uni-frankfurt.de/v2/id-cards',
},
},
},
versionHistory,
@@ -1,4 +1,4 @@
# Goethe-Uni App 3.1
# Goethe-Uni App 2.4
Wir freuen uns euch mehr in der Goethe-Uni App
bieten zu können.
@@ -1,4 +1,4 @@
# Goethe-Uni App 3.1
# Goethe-Uni App 2.4
The Goethe-Uni App got even better!
@@ -0,0 +1,15 @@
# Goethe-Uni App 2.5
Die Goethe-Uni App ist noch besser geworden!
## Komplett neue Kartenansicht
Wir haben die Karte überarbeitet, um eine klarere und schnellere Übersicht zu bieten.
## Deutschlandticket mit an Bord
Wenn du das Upgrade des Semesterticket zum Deutschlandticket gemacht hast und eingeloggt bist, findet es sich jetzt auch in der App.
## Bibliotheksdienste sind wieder voll funktionsfähig
Aufgrund einiger Adhoc-Änderungen im Bibliothekssystem haben wir die App so angepasst, dass sie damit umgehen kann.
@@ -0,0 +1,15 @@
# Goethe-Uni App 2.5
The Goethe-Uni App got even better!
## Completely new map view
We overhauled the map to offer you a clearer and faster and overview.
## Deutschlandticket included
If you upgraded your Semesterticket to a Deutschlandticket it will now reside in the App if you are logged in.
## Library services are fully functional again
Due to some adhoc changes in the library system we adjusted the app to handle them properly.
@@ -1,12 +1,6 @@
// @ts-check
import {versions} from '../../default/tools/version.js';
/** @type {import('@openstapps/core').SCAppVersionInfo[]} */
const versionHistory = await versions(
{
'3.1.0': {},
},
import.meta.url,
);
const versionHistory = await versions(import.meta.url);
export default versionHistory;
+21 -21
View File
@@ -1,7 +1,7 @@
{
"name": "@openstapps/backend",
"description": "A reference implementation for a StApps backend",
"version": "3.1.0",
"version": "4.0.6",
"private": true,
"type": "module",
"license": "AGPL-3.0-only",
@@ -43,33 +43,33 @@
"test:unit": "cross-env NODE_CONFIG_ENV=elasticsearch ALLOW_NO_TRANSPORT=true STAPPS_LOG_LEVEL=0 mocha --exit"
},
"dependencies": {
"@elastic/elasticsearch": "8.4.0",
"@elastic/elasticsearch": "8.19.2",
"@openstapps/core": "workspace:*",
"@openstapps/core-tools": "workspace:*",
"@openstapps/logger": "workspace:*",
"@types/body-parser": "1.19.2",
"@types/body-parser": "1.19.6",
"@types/cors": "2.8.13",
"@types/express": "4.17.17",
"@types/geojson": "1.0.6",
"@types/node": "18.15.3",
"@types/node": "22.15.31",
"@types/node-cron": "3.0.7",
"@types/nodemailer": "6.4.7",
"@types/nodemailer": "8.0.2",
"@types/promise-queue": "2.2.0",
"@types/uuid": "8.3.4",
"body-parser": "1.20.2",
"body-parser": "1.20.3",
"cors": "2.8.5",
"cosmiconfig": "8.1.3",
"deepmerge": "4.3.1",
"express": "4.18.2",
"express": "4.21.2",
"express-prom-bundle": "6.6.0",
"express-promise-router": "4.1.1",
"got": "12.6.0",
"moment": "2.29.4",
"morgan": "1.10.0",
"moment": "2.30.1",
"morgan": "1.10.1",
"nock": "13.3.1",
"node-cache": "5.1.2",
"node-cron": "3.0.2",
"nodemailer": "6.9.1",
"nodemailer": "8.0.11",
"prom-client": "14.1.1",
"promise-queue": "2.2.5",
"uuid": "8.3.2"
@@ -80,27 +80,27 @@
"@openstapps/prettier-config": "workspace:*",
"@openstapps/tsconfig": "workspace:*",
"@testdeck/mocha": "0.3.3",
"@types/chai": "4.3.5",
"@types/chai-as-promised": "7.1.5",
"@types/mocha": "10.0.1",
"@types/morgan": "1.9.4",
"@types/chai": "4.3.20",
"@types/chai-as-promised": "7.1.8",
"@types/mocha": "10.0.10",
"@types/morgan": "1.9.10",
"@types/sinon": "10.0.14",
"@types/sinon-express-mock": "1.3.9",
"@types/supertest": "2.0.12",
"c8": "7.14.0",
"chai": "4.3.7",
"chai-as-promised": "7.1.1",
"c8": "10.1.3",
"chai": "4.5.0",
"chai-as-promised": "7.1.2",
"cross-env": "7.0.3",
"get-port": "5.1.1",
"mocha": "10.2.0",
"mocha": "10.8.2",
"mocha-junit-reporter": "2.2.0",
"mocked-env": "1.3.5",
"sinon": "15.0.4",
"sinon-express-mock": "2.2.1",
"supertest": "6.3.3",
"ts-node": "10.9.1",
"tsup": "6.7.0",
"typescript": "5.1.6"
"ts-node": "10.9.2",
"tsup": "8.5.0",
"typescript": "5.9.3"
},
"tsup": {
"entry": [
+19 -24
View File
@@ -2,6 +2,7 @@ import {cosmiconfig, PublicExplorer} from 'cosmiconfig';
import {SCConfigFile} from '@openstapps/core';
import path from 'path';
import deepmerge from 'deepmerge';
import {Logger} from '@openstapps/logger';
const fallbackNamespace = 'default';
const configPath = 'config';
@@ -23,31 +24,25 @@ function configLoader(moduleName: string): PublicExplorer {
* Find and load a config file
*/
async function findConfig<T>(moduleName: string, namespace = fallbackNamespace): Promise<T> {
return configLoader(moduleName)
.search(path.posix.join('.', configPath, namespace))
.then(it => it!.config as T)
.catch(() =>
configLoader(moduleName)
.search(path.posix.join('.', configPath, fallbackNamespace))
.then(it => it!.config),
);
}
const config = await configLoader(moduleName).search(path.posix.join('.', configPath, namespace));
/**
* Loads a config file
*/
async function loadConfig<T>(moduleName: string): Promise<T> {
const namespace = process.env.NODE_APP_INSTANCE;
const database = process.env.NODE_CONFIG_ENV;
const config = await findConfig<T>(moduleName, namespace);
if (database) {
const databaseConfig = await findConfig<T>(database, namespace);
return deepmerge(config, databaseConfig);
if (config) {
Logger.info(`Using ${namespace} config for ${moduleName}`);
return config.config;
} else {
Logger.info(`Using ${fallbackNamespace} config for ${moduleName}`);
return configLoader(moduleName)
.search(path.posix.join('.', configPath, fallbackNamespace))
.then(it => it!.config);
}
return config;
}
export const backendConfig = await loadConfig<SCConfigFile>('backend');
export const prometheusConfig = await loadConfig<unknown>('prometheus');
const namespace = process.env.NODE_APP_INSTANCE;
const database = process.env.NODE_CONFIG_ENV;
export const prometheusConfig = await findConfig<unknown>('prometheus', namespace);
const backendConfigWithoutDatabase = await findConfig<SCConfigFile>('backend', namespace);
export const backendConfig = database
? deepmerge(backendConfigWithoutDatabase, await findConfig<never>(database, namespace))
: backendConfigWithoutDatabase;
@@ -15,7 +15,7 @@
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Logger, SMTP} from '@openstapps/logger';
import {MailOptions} from 'nodemailer/lib/sendmail-transport';
import {SendMailOptions} from 'nodemailer';
import Queue from 'promise-queue';
/**
* A queue that can send mails in serial
@@ -36,7 +36,7 @@ export class MailQueue {
* the transport gets ready this mails are getting pushed in to
* the normal queue.
*/
dryQueue: MailOptions[];
dryQueue: SendMailOptions[];
/**
* A queue that saves mails, that are being sent in series
@@ -68,7 +68,7 @@ export class MailQueue {
* Adds a mail into the queue so it gets send when the queue is ready
* @param mail Information required for sending a mail
*/
private async addToQueue(mail: MailOptions) {
private async addToQueue(mail: SendMailOptions) {
return this.queue.add<string>(() => this.transport.sendMail(mail));
}
@@ -99,7 +99,7 @@ export class MailQueue {
* Push a mail into the queue so it gets send when the queue is ready
* @param mail Information required for sending a mail
*/
public async push(mail: MailOptions) {
public async push(mail: SendMailOptions) {
if (this.transport.isVerified()) {
await this.addToQueue(mail);
} else {
+25 -1
View File
@@ -13,15 +13,34 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {SCConfigFile, SCSearchQuery, SCSearchResponse, SCThings, SCUuid} from '@openstapps/core';
import {
SCConfigFile,
SCPlace,
SCPlaceWithoutReferences,
SCSearchQuery,
SCSearchResponse,
SCThingWithCategoriesWithoutReferences,
SCThings,
SCUuid,
} from '@openstapps/core';
import {MailQueue} from '../notification/mail-queue.js';
import {Bulk} from './bulk-storage.js';
import {FeatureCollection, Point, Polygon} from 'geojson';
/**
* Creates an instance of a database
*/
export type DatabaseConstructor = new (config: SCConfigFile, mailQueue?: MailQueue) => Database;
export type SupplementaryGeoJSON = FeatureCollection<Point | Polygon, SupplementaryGeoJSONThing>;
export type SupplementaryGeoJSONThing = Pick<
Extract<SCThings, SCPlace>,
Exclude<
keyof SCPlaceWithoutReferences | keyof SCThingWithCategoriesWithoutReferences<never, never>,
'geo' | 'origin' | 'translations'
>
>;
/**
* Defines what one database class needs to have defined
*/
@@ -82,4 +101,9 @@ export interface Database {
* @param params Parameters which form a search query to search the backend data
*/
search(parameters: SCSearchQuery): Promise<SCSearchResponse>;
/**
* Get geo info for display on a map
*/
geo(): Promise<SupplementaryGeoJSON>;
}
@@ -13,12 +13,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {
AggregateName,
AggregationsAggregate,
AggregationsFiltersAggregate,
AggregationsMultiTermsBucket,
} from '@elastic/elasticsearch/lib/api/types.js';
import {estypes} from '@elastic/elasticsearch';
import {SCFacet, SCThingType} from '@openstapps/core';
/**
@@ -26,16 +21,16 @@ import {SCFacet, SCThingType} from '@openstapps/core';
* @param aggregationResponse - aggregations response from elasticsearch
*/
export function parseAggregations(
aggregationResponse: Record<AggregateName, AggregationsAggregate>,
aggregationResponse: Record<estypes.AggregateName, estypes.AggregationsAggregate>,
): SCFacet[] {
const facets: SCFacet[] = [];
for (const aggregateName in aggregationResponse) {
const aggregation = aggregationResponse[aggregateName] as AggregationsMultiTermsBucket;
const aggregation = aggregationResponse[aggregateName] as estypes.AggregationsMultiTermsBucket;
const type = aggregateName === '@all' ? {} : {onlyOnType: aggregateName as SCThingType};
for (const field in aggregation) {
const fieldAggregate = aggregation[field] as AggregationsFiltersAggregate;
const fieldAggregate = aggregation[field] as estypes.AggregationsFiltersAggregate;
if (typeof fieldAggregate !== 'object') continue;
const buckets = Object.values(fieldAggregate.buckets).map(bucket => {
@@ -14,19 +14,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Client, events} from '@elastic/elasticsearch';
import {
AggregateName,
AggregationsMultiTermsBucket,
IndicesGetAliasResponse,
SearchHit,
SearchResponse,
} from '@elastic/elasticsearch/lib/api/types.js';
import {estypes} from '@elastic/elasticsearch';
import {SCConfigFile, SCSearchQuery, SCSearchResponse, SCThings, SCUuid} from '@openstapps/core';
import {Logger} from '@openstapps/logger';
import moment from 'moment';
import {MailQueue} from '../../notification/mail-queue.js';
import {Bulk} from '../bulk-storage.js';
import {Database} from '../database.js';
import {Database, SupplementaryGeoJSON, SupplementaryGeoJSONThing} from '../database.js';
import {parseAggregations} from './aggregations.js';
import * as Monitoring from './monitoring.js';
import {buildQuery} from './query/query.js';
@@ -46,6 +40,7 @@ import {
} from './util/index.js';
import {noUndefined} from './util/no-undefined.js';
import {retryCatch, RetryOptions} from './util/retry.js';
import {Feature, Point, Polygon} from 'geojson';
/**
* A database interface for elasticsearch
@@ -84,7 +79,10 @@ export class Elasticsearch implements Database {
* @param config an assembled config file
* @param mailQueue a mail queue for monitoring
*/
constructor(private readonly config: SCConfigFile, mailQueue?: MailQueue) {
constructor(
private readonly config: SCConfigFile,
mailQueue?: MailQueue,
) {
if (config.internal.database === undefined || typeof config.internal.database.version !== 'string') {
throw new TypeError('Database version is undefined. Check your config file');
}
@@ -109,7 +107,9 @@ export class Elasticsearch implements Database {
/**
* Gets a map which contains each alias and all indices that are associated with each alias
*/
private async cleanupDeadIndices(retryOptions: Partial<RetryOptions<IndicesGetAliasResponse>> = {}) {
private async cleanupDeadIndices(
retryOptions: Partial<RetryOptions<estypes.IndicesGetAliasResponse>> = {},
) {
const aliasResponse = await retryCatch({
maxRetries: 10,
retryInterval: 2000,
@@ -143,7 +143,7 @@ export class Elasticsearch implements Database {
* @param uid an UID to use for the search
* @returns an elasticsearch object containing the thing
*/
private async getObject(uid: SCUuid): Promise<SearchHit<SCThings> | undefined> {
private async getObject(uid: SCUuid): Promise<estypes.SearchHit<SCThings> | undefined> {
const searchResponse = await this.client.search<SCThings>({
body: {
query: {
@@ -269,7 +269,9 @@ export class Elasticsearch implements Database {
/**
* Initialize the elasticsearch database (call all needed methods)
*/
public async init(retryOptions: Partial<RetryOptions<IndicesGetAliasResponse>> = {}): Promise<void> {
public async init(
retryOptions: Partial<RetryOptions<estypes.IndicesGetAliasResponse>> = {},
): Promise<void> {
const monitoringConfiguration = this.config.internal.monitoring;
if (monitoringConfiguration !== undefined) {
@@ -369,7 +371,7 @@ export class Elasticsearch implements Database {
| undefined,
};
const response: SearchResponse<SCThings> = await this.client.search({
const response: estypes.SearchResponse<SCThings> = await this.client.search({
aggs: aggregations,
query: buildQuery(parameters, this.config, esConfig),
from: parameters.from,
@@ -390,7 +392,9 @@ export class Elasticsearch implements Database {
facets:
response.aggregations === undefined
? []
: parseAggregations(response.aggregations as Record<AggregateName, AggregationsMultiTermsBucket>),
: parseAggregations(
response.aggregations as Record<estypes.AggregateName, estypes.AggregationsMultiTermsBucket>,
),
pagination: {
count: response.hits.hits.length,
offset: typeof parameters.from === 'number' ? parameters.from : 0,
@@ -402,4 +406,49 @@ export class Elasticsearch implements Database {
},
};
}
async geo(): Promise<SupplementaryGeoJSON> {
const searchResponse = await this.client.search<Extract<SCThings, {geo: unknown}>>({
body: {
query: {
exists: {
field: 'geo',
},
},
},
from: 0,
allow_no_indices: true,
index: ACTIVE_INDICES_ALIAS,
size: 1,
});
return {
type: 'FeatureCollection',
features: searchResponse.hits.hits
.map(thing => {
return thing._source?.geo
? ({
id: Number(thing._source.identifiers?.['OSM']) || undefined,
type: 'Feature',
geometry: thing._source.geo.polygon ?? thing._source.geo.point,
properties: {
name: thing._source.name,
sameAs: thing._source.sameAs,
image: thing._source.image,
alternateNames: thing._source.alternateNames,
description: thing._source.description,
identifiers: thing._source.identifiers,
categories: thing._source.categories,
categorySpecificValues: thing._source.categorySpecificValues,
openingHours: thing._source.openingHours,
address: thing._source.address,
uid: thing._source.uid,
type: thing._source.type,
},
} satisfies Feature<Polygon | Point, SupplementaryGeoJSONThing>)
: undefined;
})
.filter(noUndefined),
};
}
}
@@ -14,7 +14,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Client} from '@elastic/elasticsearch';
import {SearchRequest} from '@elastic/elasticsearch/lib/api/types.js';
import {estypes} from '@elastic/elasticsearch';
import {
SCMonitoringConfiguration,
SCMonitoringLogAction,
@@ -128,7 +128,7 @@ export async function setUp(
cron.schedule(trigger.executionTime, async () => {
// execute watch (search->condition->action)
const result = await esClient.search<SCThings>(watcher.query as SearchRequest);
const result = await esClient.search<SCThings>(watcher.query as estypes.SearchRequest);
// check conditions
const total =
@@ -12,7 +12,7 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {QueryDslFunctionScoreContainer} from '@elastic/elasticsearch/lib/api/types.js';
import {estypes} from '@elastic/elasticsearch';
import {SCBackendConfigurationSearchBoostingType} from '@openstapps/core';
import {QueryDslSpecificQueryContainer} from '../../types/util.js';
@@ -22,8 +22,8 @@ import {QueryDslSpecificQueryContainer} from '../../types/util.js';
*/
export function buildFunctionsForBoostingTypes(
boostingTypes: SCBackendConfigurationSearchBoostingType[],
): QueryDslFunctionScoreContainer[] {
const functions: QueryDslFunctionScoreContainer[] = [];
): estypes.QueryDslFunctionScoreContainer[] {
const functions: estypes.QueryDslFunctionScoreContainer[] = [];
for (const boostingForOneSCType of boostingTypes) {
const typeFilter: QueryDslSpecificQueryContainer<'term'> = {
@@ -12,7 +12,7 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {QueryDslFunctionScoreContainer} from '@elastic/elasticsearch/lib/api/types.js';
import {estypes} from '@elastic/elasticsearch';
import {SCBackendConfigurationSearchBoostingContext, SCSearchContext} from '@openstapps/core';
import {buildFunctionsForBoostingTypes} from './boost-functions.js';
@@ -24,7 +24,7 @@ import {buildFunctionsForBoostingTypes} from './boost-functions.js';
export function buildScoringFunctions(
boostings: SCBackendConfigurationSearchBoostingContext,
context: SCSearchContext | undefined,
): QueryDslFunctionScoreContainer[] {
): estypes.QueryDslFunctionScoreContainer[] {
// default context
let functions = buildFunctionsForBoostingTypes(boostings['default' as SCSearchContext]);
@@ -12,7 +12,7 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {QueryDslQueryContainer} from '@elastic/elasticsearch/lib/api/types.js';
import {estypes} from '@elastic/elasticsearch';
import {SCSearchFilter} from '@openstapps/core';
import {buildBooleanFilter} from './filters/boolean.js';
import {buildAvailabilityFilter} from './filters/availability.js';
@@ -26,7 +26,7 @@ import {buildValueFilter} from './filters/value.js';
* Converts Array of Filters to elasticsearch query-syntax
* @param filter A search filter for the retrieval of the data
*/
export function buildFilter(filter: SCSearchFilter): QueryDslQueryContainer {
export function buildFilter(filter: SCSearchFilter): estypes.QueryDslQueryContainer {
switch (filter.type) {
case 'value': {
return buildValueFilter(filter);
@@ -12,7 +12,7 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {QueryDslBoolQuery} from '@elastic/elasticsearch/lib/api/types.js';
import {estypes} from '@elastic/elasticsearch';
import {SCSearchBooleanFilter} from '@openstapps/core';
import {QueryDslSpecificQueryContainer} from '../../types/util.js';
import {buildFilter} from '../filter.js';
@@ -22,7 +22,7 @@ import {buildFilter} from '../filter.js';
* @param filter A search filter for the retrieval of the data
*/
export function buildBooleanFilter(filter: SCSearchBooleanFilter): QueryDslSpecificQueryContainer<'bool'> {
const result: QueryDslBoolQuery = {
const result: estypes.QueryDslBoolQuery = {
minimum_should_match: 0,
must: [],
must_not: [],
@@ -12,7 +12,7 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {QueryDslDateRangeQuery} from '@elastic/elasticsearch/lib/api/types.js';
import {estypes} from '@elastic/elasticsearch';
import {SCSearchDateRangeFilter} from '@openstapps/core';
import {QueryDslSpecificQueryContainer} from '../../types/util.js';
@@ -23,7 +23,7 @@ import {QueryDslSpecificQueryContainer} from '../../types/util.js';
export function buildDateRangeFilter(
filter: SCSearchDateRangeFilter,
): QueryDslSpecificQueryContainer<'range'> {
const dateRangeObject: QueryDslDateRangeQuery = {
const dateRangeObject: estypes.QueryDslDateRangeQuery = {
format: filter.arguments.format,
time_zone: filter.arguments.timeZone,
relation: filter.arguments.relation,
@@ -12,7 +12,7 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {QueryDslGeoDistanceQuery} from '@elastic/elasticsearch/lib/api/types.js';
import {estypes} from '@elastic/elasticsearch';
import {SCSearchDistanceFilter} from '@openstapps/core';
import {QueryDslSpecificQueryContainer} from '../../types/util.js';
@@ -23,9 +23,9 @@ import {QueryDslSpecificQueryContainer} from '../../types/util.js';
export function buildDistanceFilter(
filter: SCSearchDistanceFilter,
): QueryDslSpecificQueryContainer<'geo_distance'> {
const geoObject: QueryDslGeoDistanceQuery = {
const geoObject: estypes.QueryDslGeoDistanceQuery = {
distance: `${filter.arguments.distance}m`,
[`${filter.arguments.field}.point.coordinates`]: {
[`${filter.arguments.field}.point`]: {
lat: filter.arguments.position[1],
lon: filter.arguments.position[0],
},
@@ -19,14 +19,29 @@ import {QueryDslSpecificQueryContainer} from '../../types/util.js';
* Converts a geo filter to elasticsearch syntax
* @param filter A search filter for the retrieval of the data
*/
export function buildGeoFilter(filter: SCGeoFilter): QueryDslSpecificQueryContainer<'geo_shape'> {
export function buildGeoFilter(filter: SCGeoFilter): QueryDslSpecificQueryContainer<'bool'> {
return {
geo_shape: {
ignore_unmapped: true,
[`${filter.arguments.field}.polygon`]: {
shape: filter.arguments.shape,
relation: filter.arguments.spatialRelation,
},
bool: {
should: [
{
geo_shape: {
ignore_unmapped: true,
[`${filter.arguments.field}.polygon`]: {
shape: filter.arguments.shape,
relation: filter.arguments.spatialRelation,
},
},
} satisfies QueryDslSpecificQueryContainer<'geo_shape'>,
{
geo_shape: {
ignore_unmapped: true,
[`${filter.arguments.field}.point`]: {
shape: filter.arguments.shape,
relation: filter.arguments.spatialRelation,
},
},
} satisfies QueryDslSpecificQueryContainer<'geo_shape'>,
],
},
};
}
@@ -12,7 +12,7 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {QueryDslNumberRangeQuery} from '@elastic/elasticsearch/lib/api/types.js';
import {estypes} from '@elastic/elasticsearch';
import {SCSearchNumericRangeFilter} from '@openstapps/core';
import {QueryDslSpecificQueryContainer} from '../../types/util.js';
@@ -23,7 +23,7 @@ import {QueryDslSpecificQueryContainer} from '../../types/util.js';
export function buildNumericRangeFilter(
filter: SCSearchNumericRangeFilter,
): QueryDslSpecificQueryContainer<'range'> {
const numericRangeObject: QueryDslNumberRangeQuery = {
const numericRangeObject: estypes.QueryDslNumberRangeQuery = {
relation: filter.arguments.relation,
};
if (filter.arguments.bounds.lowerBound?.mode === 'exclusive') {
@@ -21,16 +21,31 @@ import {QueryDslSpecificQueryContainer} from '../../types/util.js';
*/
export function buildValueFilter(
filter: SCSearchValueFilter,
): QueryDslSpecificQueryContainer<'term'> | QueryDslSpecificQueryContainer<'terms'> {
return Array.isArray(filter.arguments.value)
? {
terms: {
[`${filter.arguments.field}.raw`]: filter.arguments.value,
):
| QueryDslSpecificQueryContainer<'exists'>
| QueryDslSpecificQueryContainer<'term'>
| QueryDslSpecificQueryContainer<'terms'> {
switch (typeof filter.arguments.value) {
case 'undefined': {
return {
exists: {
field: filter.arguments.field,
},
}
: {
};
}
case 'string': {
return {
term: {
[`${filter.arguments.field}.raw`]: filter.arguments.value,
},
};
}
case 'object': {
return {
terms: {
[`${filter.arguments.field}.raw`]: filter.arguments.value,
},
};
}
}
}
@@ -12,7 +12,7 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {QueryDslQueryContainer} from '@elastic/elasticsearch/lib/api/types.js';
import {estypes} from '@elastic/elasticsearch';
import {SCConfigFile, SCSearchQuery} from '@openstapps/core';
import {ElasticsearchConfig} from '../types/elasticsearch-config.js';
import {buildFilter} from './filter.js';
@@ -29,7 +29,7 @@ export const buildQuery = function buildQuery(
parameters: SCSearchQuery,
defaultConfig: SCConfigFile,
elasticsearchConfig: ElasticsearchConfig,
): QueryDslQueryContainer {
): estypes.QueryDslQueryContainer {
// if config provides a minMatch parameter, we use query_string instead of a match query
let query;
if (elasticsearchConfig.query === undefined) {
@@ -83,7 +83,7 @@ export const buildQuery = function buildQuery(
);
}
const functionScoreQuery: QueryDslQueryContainer = {
const functionScoreQuery: estypes.QueryDslQueryContainer = {
function_score: {
functions: buildScoringFunctions(defaultConfig.internal.boostings, parameters.context),
query: {
@@ -97,7 +97,8 @@ export const buildQuery = function buildQuery(
},
};
const mustMatch = functionScoreQuery.function_score?.query?.bool?.must;
const mustMatch = (functionScoreQuery.function_score as estypes.QueryDslFunctionScoreQuery | undefined)
?.query?.bool?.must;
if (Array.isArray(mustMatch)) {
if (query !== undefined) {
@@ -12,7 +12,7 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Sort} from '@elastic/elasticsearch/lib/api/types.js';
import {estypes} from '@elastic/elasticsearch';
import {SCSearchSort} from '@openstapps/core';
import {buildDistanceSort} from './sort/distance.js';
import {buildDucetSort} from './sort/ducet.js';
@@ -24,7 +24,7 @@ import {buildPriceSort} from './sort/price.js';
* @param sorts Sorting rules to apply to the data that is being queried
* @returns an array of sort queries
*/
export const buildSort = function buildSort(sorts: SCSearchSort[]): Sort {
export const buildSort = function buildSort(sorts: SCSearchSort[]): estypes.Sort {
return sorts.map(sort => {
switch (sort.type) {
case 'generic': {
@@ -12,20 +12,20 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {SortOptions} from '@elastic/elasticsearch/lib/api/types.js';
import {estypes} from '@elastic/elasticsearch';
import {SCDistanceSort} from '@openstapps/core';
/**
* Converts a distance sort to elasticsearch syntax
* @param sort A sorting definition
*/
export function buildDistanceSort(sort: SCDistanceSort): SortOptions {
export function buildDistanceSort(sort: SCDistanceSort): estypes.SortOptions {
return {
_geo_distance: {
mode: 'avg',
order: sort.order,
unit: 'm',
[`${sort.arguments.field}.point.coordinates`]: {
[`${sort.arguments.field}.point`]: {
lat: sort.arguments.position[1],
lon: sort.arguments.position[0],
},
@@ -12,14 +12,14 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {SortOptions} from '@elastic/elasticsearch/lib/api/types.js';
import {estypes} from '@elastic/elasticsearch';
import {SCDucetSort} from '@openstapps/core';
/**
* Converts a ducet sort to elasticsearch syntax
* @param sort A sorting definition
*/
export function buildDucetSort(sort: SCDucetSort): SortOptions {
export function buildDucetSort(sort: SCDucetSort): estypes.SortOptions {
return {
[`${sort.arguments.field}.sort`]: sort.order,
};
@@ -12,14 +12,14 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {SortOptions} from '@elastic/elasticsearch/lib/api/types.js';
import {estypes} from '@elastic/elasticsearch';
import {SCGenericSort} from '@openstapps/core';
/**
* Converts a generic sort to elasticsearch syntax
* @param sort A sorting definition
*/
export function buildGenericSort(sort: SCGenericSort): SortOptions {
export function buildGenericSort(sort: SCGenericSort): estypes.SortOptions {
return {
[sort.arguments.field]: sort.order,
};
@@ -12,14 +12,14 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {SortOptions} from '@elastic/elasticsearch/lib/api/types.js';
import {estypes} from '@elastic/elasticsearch';
import {SCPriceSort, SCSportCoursePriceGroup, SCThingsField} from '@openstapps/core';
/**
* Converts a price sort to elasticsearch syntax
* @param sort A sorting definition
*/
export function buildPriceSort(sort: SCPriceSort): SortOptions {
export function buildPriceSort(sort: SCPriceSort): estypes.SortOptions {
return {
_script: {
order: sort.order,
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Client} from '@elastic/elasticsearch';
import {Client, estypes} from '@elastic/elasticsearch';
import {SCThingType} from '@openstapps/core';
import type {AggregationSchema} from '@openstapps/core/lib/mappings/aggregations.json.js';
import type {ElasticsearchTemplateCollection} from '@openstapps/core/lib/mappings/mappings.json.js';
@@ -36,7 +36,10 @@ export const aggregations = JSON.parse(
* @param client An elasticsearch client to use
* @param type the SCThingType of which the template should be set
*/
export async function putTemplate(client: Client, type: SCThingType) {
export async function putTemplate(
client: Client,
type: SCThingType,
): Promise<estypes.IndicesPutTemplateResponse> {
const sanitizedType = `template_${type.replaceAll(/\s/g, '_')}`;
return client.indices.putTemplate({
@@ -12,8 +12,8 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {QueryDslQueryContainer} from '@elastic/elasticsearch/lib/api/types.js';
import {estypes} from '@elastic/elasticsearch';
export type QueryDslSpecificQueryContainer<T extends keyof QueryDslQueryContainer> = Required<
Pick<QueryDslQueryContainer, T>
export type QueryDslSpecificQueryContainer<T extends keyof estypes.QueryDslQueryContainer> = Required<
Pick<estypes.QueryDslQueryContainer, T>
>;
+5 -2
View File
@@ -22,7 +22,7 @@ import http from 'http';
import {MailQueue} from '../src/notification/mail-queue.js';
import {Bulk, BulkStorage} from '../src/storage/bulk-storage.js';
import getPort from 'get-port';
import {Database} from '../src/storage/database.js';
import {Database, SupplementaryGeoJSON} from '../src/storage/database.js';
import {v4} from 'uuid';
import {backendConfig} from '../src/config.js';
import {getIndexUID} from '../src/storage/elasticsearch/util/index.js';
@@ -58,7 +58,6 @@ export async function startApp(): Promise<Express> {
* An elasticsearch mock
*/
export class ElasticsearchMock implements Database {
// @ts-expect-error never read
private bulk: Bulk | undefined;
private storageMock = new Map<string, SCThings>();
@@ -67,6 +66,10 @@ export class ElasticsearchMock implements Database {
// Nothing to do here
}
geo(): Promise<SupplementaryGeoJSON> {
throw new Error('Method not implemented.');
}
bulkCreated(bulk: Bulk): Promise<void> {
this.bulk = bulk;
return Promise.resolve(undefined);
@@ -19,7 +19,7 @@ import sinon from 'sinon';
import {MailQueue} from '../../src/notification/mail-queue.js';
import {expect} from 'chai';
import Queue from 'promise-queue';
import {MailOptions} from 'nodemailer/lib/sendmail-transport';
import {SendMailOptions} from 'nodemailer';
import {getTransport, TRANSPORT_SEND_RESPONSE} from '../common.js';
describe('MailQueue', async function () {
@@ -54,7 +54,7 @@ describe('MailQueue', async function () {
const transport = getTransport(false);
// @ts-expect-error not assignable
const mailQueue = new MailQueue(transport);
const mail: MailOptions = {from: 'Foo', subject: 'Foo Subject'};
const mail: SendMailOptions = {from: 'Foo', subject: 'Foo Subject'};
for (let i = 0; i < numberOfMails; i++) {
await mailQueue.push(mail);
}
@@ -70,7 +70,7 @@ describe('MailQueue', async function () {
const queueAddStub = sandbox.stub(Queue.prototype, 'add');
// @ts-expect-error not assignable
const mailQueue = new MailQueue(getTransport(false));
const mail: MailOptions = {};
const mail: SendMailOptions = {};
mailQueue.push(mail);
expect(queueAddStub.called).to.be.false;
@@ -81,7 +81,7 @@ describe('MailQueue', async function () {
const transport = getTransport(false);
// @ts-expect-error not assignable
const mailQueue = new MailQueue(transport);
const mail: MailOptions = {from: 'Foo', subject: 'Foo Subject'};
const mail: SendMailOptions = {from: 'Foo', subject: 'Foo Subject'};
// fake that transport is verified
transport.isVerified = () => true;
mailQueue.push(mail);
@@ -97,7 +97,7 @@ describe('MailQueue', async function () {
const transport = getTransport(false);
// @ts-expect-error not assignable
const mailQueue = new MailQueue(transport);
const mail: MailOptions = {from: 'Foo', subject: 'Foo Subject'};
const mail: SendMailOptions = {from: 'Foo', subject: 'Foo Subject'};
// fake that transport is verified
transport.isVerified = () => true;
await mailQueue.push(mail);
+17 -15
View File
@@ -14,6 +14,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {
SCBook,
SCBulkAddRoute,
SCBulkDoneRoute,
SCBulkRequest,
@@ -23,29 +24,30 @@ import {
import {expect} from 'chai';
import {bulk, DEFAULT_TEST_TIMEOUT} from '../common.js';
import {testApp} from '../tests-setup.js';
import {readFile} from 'fs/promises';
import {v4} from 'uuid';
import bookFile from '@openstapps/core/test/resources/indexable/Book.2.json' with {type: 'json'};
const book = JSON.parse(
await readFile('node_modules/@openstapps/core/test/resources/indexable/Book.2.json', 'utf8'),
).instance;
const book = bookFile.instance as SCBook;
describe('Bulk routes', async function () {
// increase timeout for the suite
this.timeout(DEFAULT_TEST_TIMEOUT);
const request: SCBulkRequest = {
expiration: bulk.expiration,
source: bulk.source,
type: bulk.type,
};
const bulkRoute = new SCBulkRoute();
const bulkAddRoute = new SCBulkAddRoute();
const bulkDoneRoute = new SCBulkDoneRoute();
let request: SCBulkRequest;
let bulkRoute: SCBulkRoute;
let bulkAddRoute: SCBulkAddRoute;
let bulkDoneRoute: SCBulkDoneRoute;
// afterEach(async function() {
// TODO: Delete saved bulks
// });
before(function () {
request = {
expiration: bulk.expiration,
source: bulk.source,
type: bulk.type,
};
bulkRoute = new SCBulkRoute();
bulkAddRoute = new SCBulkAddRoute();
bulkDoneRoute = new SCBulkDoneRoute();
});
it('should create bulk', async function () {
const {status, body, error} = await testApp
@@ -21,7 +21,12 @@ import {expect} from 'chai';
describe('Index route', async function () {
// increase timeout for the suite
this.timeout(DEFAULT_TEST_TIMEOUT);
const indexRoute = new SCIndexRoute();
let indexRoute: SCIndexRoute;
before(function () {
indexRoute = new SCIndexRoute();
});
it('should respond with both app and backend configuration', async function () {
const request: SCIndexRequest = {};
@@ -30,15 +30,11 @@ import chaiAsPromised from 'chai-as-promised';
import {DEFAULT_TEST_TIMEOUT} from '../common.js';
import {testApp} from '../tests-setup.js';
import {backendConfig} from '../../src/config.js';
import {readFile} from 'fs/promises';
import registerRequest from '@openstapps/core/test/resources/PluginRegisterRequest.1.json' with {type: 'json'};
// for using promises in expectations (to.eventually.be...)
use(chaiAsPromised);
const registerRequest = JSON.parse(
await readFile('node_modules/@openstapps/core/test/resources/PluginRegisterRequest.1.json', 'utf8'),
);
// cast it because of "TS2322: Type 'string' is not assignable to type '"add"'"
export const registerAddRequest: SCPluginAdd = registerRequest.instance as SCPluginAdd;
+5 -2
View File
@@ -47,8 +47,8 @@ describe('Create route', async function () {
const statusCodeSuccess = 222;
const bodySuccess = {foo: true};
const sandbox = sinon.createSandbox();
const validationError = new SCValidationErrorResponse([]);
const internalServerError = new SCInternalServerErrorResponse();
let validationError: SCValidationErrorResponse;
let internalServerError: SCInternalServerErrorResponse;
beforeEach(function () {
app = express();
@@ -64,6 +64,9 @@ describe('Create route', async function () {
handler = (_request, _app) => {
return Promise.resolve(bodySuccess);
};
validationError = new SCValidationErrorResponse([]);
internalServerError = new SCInternalServerErrorResponse();
});
afterEach(function () {
@@ -29,14 +29,21 @@ import {backendConfig} from '../../src/config.js';
describe('Search route', async function () {
// increase timeout for the suite
this.timeout(DEFAULT_TEST_TIMEOUT);
const searchRoute = new SCSearchRoute();
const multiSearchRoute = new SCMultiSearchRoute();
const syntaxError = new SCSyntaxErrorResponse('Foo Message');
const methodNotAllowedError = new SCMethodNotAllowedErrorResponse();
const tooManyRequestsError = new SCTooManyRequestsErrorResponse();
let searchRoute: SCSearchRoute;
let multiSearchRoute: SCMultiSearchRoute;
let syntaxError: SCSyntaxErrorResponse;
let methodNotAllowedError: SCMethodNotAllowedErrorResponse;
let tooManyRequestsError: SCTooManyRequestsErrorResponse;
before(function () {
searchRoute = new SCSearchRoute();
multiSearchRoute = new SCMultiSearchRoute();
syntaxError = new SCSyntaxErrorResponse('Foo Message');
methodNotAllowedError = new SCMethodNotAllowedErrorResponse();
tooManyRequestsError = new SCTooManyRequestsErrorResponse();
});
it('should reject GET, PUT with a valid search query', async function () {
// const expectedParams = JSON.parse(JSON.stringify(defaultParams));
const {status} = await testApp.get('/search').set('Accept', 'application/json').send({
query: 'Some search terms',
});
@@ -13,23 +13,25 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {SCThingUpdateRoute} from '@openstapps/core';
import {SCBook, SCThingUpdateRoute} from '@openstapps/core';
import chaiAsPromised from 'chai-as-promised';
import {bulkStorageMock, DEFAULT_TEST_TIMEOUT} from '../common.js';
import {expect, use} from 'chai';
import {testApp} from '../tests-setup.js';
import {readFile} from 'fs/promises';
import bookFile from '@openstapps/core/test/resources/indexable/Book.1.json' with {type: 'json'};
use(chaiAsPromised);
const book = JSON.parse(
await readFile('node_modules/@openstapps/core/test/resources/indexable/Book.1.json', 'utf8'),
).instance;
const book = bookFile.instance as SCBook;
describe('Thing update route', async function () {
// increase timeout for the suite
this.timeout(DEFAULT_TEST_TIMEOUT);
const thingUpdateRoute = new SCThingUpdateRoute();
let thingUpdateRoute: SCThingUpdateRoute;
before(function () {
thingUpdateRoute = new SCThingUpdateRoute();
});
it('should update a thing', async function () {
const thingUpdateRouteurlPath = thingUpdateRoute.urlPath
@@ -13,13 +13,13 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {AggregateName, AggregationsMultiTermsBucket} from '@elastic/elasticsearch/lib/api/types.js';
import {estypes} from '@elastic/elasticsearch';
import {SCFacet, SCThingType} from '@openstapps/core';
import {expect} from 'chai';
import {parseAggregations} from '../../../src/storage/elasticsearch/aggregations.js';
describe('Aggregations', function () {
const aggregations: Record<AggregateName, Partial<AggregationsMultiTermsBucket>> = {
const aggregations: Record<estypes.AggregateName, Partial<estypes.AggregationsMultiTermsBucket>> = {
'catalog': {
'doc_count': 4,
'superCatalogs.categories': {
@@ -14,9 +14,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Client, Diagnostic} from '@elastic/elasticsearch';
import Indices from '@elastic/elasticsearch/lib/api/api/indices.js';
import {CreateResponse, SearchHit, SearchResponse} from '@elastic/elasticsearch/lib/api/types.js';
import {Client, Diagnostic, estypes} from '@elastic/elasticsearch';
import {
SCBook,
SCBulkResponse,
@@ -39,7 +37,6 @@ import {Elasticsearch} from '../../../src/storage/elasticsearch/elasticsearch.js
import {bulk, DEFAULT_TEST_TIMEOUT, getTransport, getIndex} from '../../common.js';
import fs from 'fs';
import {backendConfig} from '../../../src/config.js';
import {readFile} from 'fs/promises';
import {
ACTIVE_INDICES_ALIAS,
getIndexUID,
@@ -50,23 +47,22 @@ import {
} from '../../../src/storage/elasticsearch/util/index.js';
import cron from 'node-cron';
import {query} from './query.js';
import messageFile from '@openstapps/core/test/resources/indexable/Message.1.json' with {type: 'json'};
import bookFile from '@openstapps/core/test/resources/indexable/Book.1.json' with {type: 'json'};
const indicesPrototype = Object.getPrototypeOf(new Client({node: 'http://localhost:9200'}).indices);
const message = messageFile.instance as SCMessage;
const book = bookFile.instance as SCBook;
use(chaiAsPromised);
/**
*
*/
function searchResponse<T>(...hits: SearchHit<T>[]): SearchResponse<T> {
function searchResponse<T>(...hits: estypes.SearchHit<T>[]): estypes.SearchResponse<T> {
return {hits: {hits}, took: 0, timed_out: false, _shards: {total: 1, failed: 0, successful: 1}};
}
const message = JSON.parse(
await readFile('node_modules/@openstapps/core/test/resources/indexable/Message.1.json', 'utf8'),
);
const book = JSON.parse(
await readFile('node_modules/@openstapps/core/test/resources/indexable/Book.1.json', 'utf8'),
);
describe('Elasticsearch', function () {
// increase timeout for the suite
this.timeout(DEFAULT_TEST_TIMEOUT);
@@ -74,8 +70,15 @@ describe('Elasticsearch', function () {
before(function () {
// eslint-disable-next-line no-console
console.log('before');
sandbox.stub(fs, 'readFileSync').returns('{}');
sandbox.stub(backendConfig.internal.boostings.default[0], 'fields').value({
'academicTerms.acronym': {
'SS 2023': 1.05,
'WS 2023/24': 1.1,
'SoSe 2023': 1.05,
'WiSe 2023/24': 1.1,
},
});
});
after(function () {
sandbox.restore();
@@ -308,13 +311,13 @@ describe('Elasticsearch', function () {
beforeEach(function () {
sandbox
.stub(Indices.default.prototype, 'getAlias')
.stub(indicesPrototype, 'getAlias')
.resolves({[oldIndex]: {aliases: {[SCThingType.Book]: {}}}} as any);
sandbox.stub(Indices.default.prototype, 'putTemplate').resolves({} as any);
createStub = sandbox.stub(Indices.default.prototype, 'create').resolves({} as any);
deleteStub = sandbox.stub(Indices.default.prototype, 'delete').resolves({} as any);
refreshStub = sandbox.stub(Indices.default.prototype, 'refresh').resolves({} as any);
updateAliasesStub = sandbox.stub(Indices.default.prototype, 'updateAliases').resolves({} as any);
sandbox.stub(indicesPrototype, 'putTemplate').resolves({} as any);
createStub = sandbox.stub(indicesPrototype, 'create').resolves({} as any);
deleteStub = sandbox.stub(indicesPrototype, 'delete').resolves({} as any);
refreshStub = sandbox.stub(indicesPrototype, 'refresh').resolves({} as any);
updateAliasesStub = sandbox.stub(indicesPrototype, 'updateAliases').resolves({} as any);
es = new Elasticsearch(backendConfig);
});
@@ -441,11 +444,11 @@ describe('Elasticsearch', function () {
});
it('should provide the thing if object is found', async function () {
const foundObject: SearchHit<SCMessage> = {
const foundObject: estypes.SearchHit<SCMessage> = {
_id: '',
_index: '',
_score: 0,
_source: message as SCMessage,
_source: message,
};
sandbox.stub(es.client, 'search').resolves(searchResponse(foundObject));
@@ -462,7 +465,7 @@ describe('Elasticsearch', function () {
});
beforeEach(function () {
sandbox.stub(Indices.default.prototype, 'getAlias').resolves({} as any);
sandbox.stub(indicesPrototype, 'getAlias').resolves({} as any);
});
afterEach(function () {
@@ -472,10 +475,10 @@ describe('Elasticsearch', function () {
it('should not post if the object already exists in an index which will not be rolled over', async function () {
const index = getIndex();
const oldIndex = index.replace('foosource', 'barsource');
const object: SearchHit<SCMessage> = {
const object: estypes.SearchHit<SCMessage> = {
_id: '',
_index: oldIndex,
_source: message as SCMessage,
_source: message,
};
sandbox.stub(es.client, 'search').resolves(searchResponse<SCMessage>(object));
sandbox.stub(es, 'prepareBulkWrite').resolves(index);
@@ -486,10 +489,10 @@ describe('Elasticsearch', function () {
it('should reject if there is an object creation error on the elasticsearch side', async function () {
sandbox.stub(es.client, 'search').resolves(searchResponse());
sandbox.stub(es.client, 'create').resolves({result: 'not_found'} as CreateResponse);
sandbox.stub(es.client, 'create').resolves({result: 'not_found'} as estypes.CreateResponse);
await es.init();
return expect(es.post(message as SCMessage, bulk)).to.rejectedWith('creation');
return expect(es.post(message, bulk)).to.rejectedWith('creation');
});
it('should create a new object', async function () {
@@ -502,7 +505,7 @@ describe('Elasticsearch', function () {
});
await es.init();
await es.post(message as SCMessage, bulk);
await es.post(message, bulk);
expect(createStub.called).to.be.true;
expect(caughtParameter.document).to.be.eql({
@@ -523,11 +526,11 @@ describe('Elasticsearch', function () {
sandbox.restore();
});
it('should reject to put if the object does not already exist', async function () {
const object: SearchHit<SCMessage> = {
const object: estypes.SearchHit<SCMessage> = {
_id: '',
_index: getIndex(),
_score: 0,
_source: message as SCMessage,
_source: message,
};
sandbox.stub(es.client, 'search').resolves(searchResponse());
@@ -537,11 +540,11 @@ describe('Elasticsearch', function () {
// noinspection JSUnusedLocalSymbols
it('should update the object if it already exists', async function () {
let caughtParameter: any;
const object: SearchHit<SCMessage> = {
const object: estypes.SearchHit<SCMessage> = {
_id: '',
_index: getIndex(),
_score: 0,
_source: message as SCMessage,
_source: message,
};
sandbox.stub(es.client, 'search').resolves(searchResponse(object));
// @ts-expect-error unused
@@ -560,17 +563,17 @@ describe('Elasticsearch', function () {
describe('search', async function () {
let es: Elasticsearch;
const sandbox = sinon.createSandbox();
const objectMessage: SearchHit<SCMessage> = {
const objectMessage: estypes.SearchHit<SCMessage> = {
_id: '123',
_index: getIndex(),
_score: 0,
_source: message as SCMessage,
_source: message,
};
const objectBook: SearchHit<SCBook> = {
const objectBook: estypes.SearchHit<SCBook> = {
_id: '321',
_index: getIndex(),
_score: 0,
_source: book as SCBook,
_source: book,
};
const fakeEsAggregations = {
'@all': {
@@ -591,7 +594,7 @@ describe('Elasticsearch', function () {
},
},
};
const fakeSearchResponse: SearchResponse<SCThings> = {
const fakeSearchResponse: estypes.SearchResponse<SCThings> = {
took: 12,
timed_out: false,
// @ts-expect-error not assignable
@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import {Client} from '@elastic/elasticsearch';
import {SearchResponse} from '@elastic/elasticsearch/lib/api/types.js';
import {estypes} from '@elastic/elasticsearch';
import {
SCMonitoringConfiguration,
SCMonitoringLogAction,
@@ -111,7 +111,7 @@ describe('Monitoring', async function () {
});
it('should log errors where conditions failed', async function () {
const fakeSearchResponse: SearchResponse<SCThings> = {
const fakeSearchResponse: estypes.SearchResponse<SCThings> = {
took: 12,
timed_out: false,
// @ts-expect-error not assignable
@@ -31,7 +31,7 @@ import {buildQuery} from '../../../src/storage/elasticsearch/query/query.js';
import {buildSort} from '../../../src/storage/elasticsearch/query/sort.js';
import {ElasticsearchConfig} from '../../../src/storage/elasticsearch/types/elasticsearch-config.js';
import {QueryDslSpecificQueryContainer} from '../../../src/storage/elasticsearch/types/util.js';
import {QueryDslRangeQuery, SortCombinations} from '@elastic/elasticsearch/lib/api/types.js';
import {estypes} from '@elastic/elasticsearch';
import {backendConfig} from '../../../src/config.js';
describe('Query', function () {
@@ -364,9 +364,9 @@ describe('Query', function () {
expect(filter).to.deep.equal(expectedFilter);
for (const bound of ['g', 'l']) {
const inclusiveExists =
typeof filter.range.price?.[`${bound}t` as keyof QueryDslRangeQuery] !== 'undefined';
typeof filter.range.price?.[`${bound}t` as keyof estypes.QueryDslRangeQuery] !== 'undefined';
const exclusiveExists =
typeof filter.range.price?.[`${bound}te` as keyof QueryDslRangeQuery] !== 'undefined';
typeof filter.range.price?.[`${bound}te` as keyof estypes.QueryDslRangeQuery] !== 'undefined';
// only one should exist at the same time
expect(inclusiveExists && exclusiveExists).to.be.false;
@@ -466,7 +466,7 @@ describe('Query', function () {
const expectedFilter: QueryDslSpecificQueryContainer<'geo_distance'> = {
geo_distance: {
'distance': '1000m',
'geo.point.coordinates': {
'geo.point': {
lat: 8.123,
lon: 50.123,
},
@@ -479,18 +479,39 @@ describe('Query', function () {
it('should build geo filter for shapes and points', function () {
const filter = buildFilter(searchFilters.geoPoint);
const expectedFilter = {
geo_shape: {
'geo.polygon': {
relation: undefined,
shape: {
type: 'envelope',
coordinates: [
[50.123, 8.123],
[50.123, 8.123],
],
bool: {
should: [
{
geo_shape: {
'geo.polygon': {
relation: undefined,
shape: {
coordinates: [
[50.123, 8.123],
[50.123, 8.123],
],
type: 'envelope',
},
},
'ignore_unmapped': true,
},
},
},
'ignore_unmapped': true,
{
geo_shape: {
'geo.point': {
relation: undefined,
shape: {
coordinates: [
[50.123, 8.123],
[50.123, 8.123],
],
type: 'envelope',
},
},
'ignore_unmapped': true,
},
},
],
},
};
@@ -500,18 +521,39 @@ describe('Query', function () {
it('should build geo filter for shapes only', function () {
const filter = buildFilter(searchFilters.geoShape);
const expectedFilter = {
geo_shape: {
'geo.polygon': {
relation: 'contains',
shape: {
type: 'envelope',
coordinates: [
[50.123, 8.123],
[50.123, 8.123],
],
bool: {
should: [
{
geo_shape: {
'geo.polygon': {
relation: 'contains',
shape: {
coordinates: [
[50.123, 8.123],
[50.123, 8.123],
],
type: 'envelope',
},
},
'ignore_unmapped': true,
},
},
},
'ignore_unmapped': true,
{
geo_shape: {
'geo.point': {
relation: 'contains',
shape: {
coordinates: [
[50.123, 8.123],
[50.123, 8.123],
],
type: 'envelope',
},
},
'ignore_unmapped': true,
},
},
],
},
};
@@ -581,8 +623,8 @@ describe('Query', function () {
},
},
];
let sorts: SortCombinations[] = [];
const expectedSorts: {[key: string]: SortCombinations} = {
let sorts: estypes.SortCombinations[] = [];
const expectedSorts: {[key: string]: estypes.SortCombinations} = {
ducet: {
'name.sort': 'desc',
},
@@ -594,7 +636,7 @@ describe('Query', function () {
'mode': 'avg',
'order': 'desc',
'unit': 'm',
'geo.point.coordinates': {
'geo.point': {
lat: 50.123,
lon: 8.123,
},
@@ -609,7 +651,7 @@ describe('Query', function () {
},
};
before(function () {
sorts = buildSort(searchSCSearchSort) as SortCombinations[];
sorts = buildSort(searchSCSearchSort) as estypes.SortCombinations[];
});
it('should build ducet sort', function () {
@@ -1,6 +1,6 @@
import {QueryDslQueryContainer} from '@elastic/elasticsearch/lib/api/types.js';
import {estypes} from '@elastic/elasticsearch';
export const query: QueryDslQueryContainer = {
export const query: estypes.QueryDslQueryContainer = {
function_score: {
functions: [
{
+3 -3
View File
@@ -2,7 +2,7 @@
"extends": "@openstapps/tsconfig",
"compilerOptions": {
"resolveJsonModule": true,
"useUnknownInCatchVariables": false,
"allowJs": true
}
"useUnknownInCatchVariables": false
},
"exclude": ["lib", "app.js"]
}
+18
View File
@@ -1,5 +1,23 @@
# @openstapps/database
## 4.0.1
### Patch Changes
- b40ba7ad: Updated Elasticsearch dependency
## 4.0.0
### Major Changes
- c8e29020: Update to Node 22
## 3.2.0
### Patch Changes
- 689ac68b: pin alpine version to 3.18 and add healthchecks
## 3.0.0
### Patch Changes
+3 -1
View File
@@ -1,4 +1,4 @@
FROM elasticsearch:8.4.2
FROM elasticsearch:8.19.21
EXPOSE 9200
EXPOSE 9300
@@ -14,4 +14,6 @@ RUN chown elasticsearch:elasticsearch config/elasticsearch.yml
USER elasticsearch
HEALTHCHECK --interval=10s --timeout=10s --start-period=60s --retries=12 CMD curl --fail -s http://localhost:9200/ >/dev/null || exit 1
CMD ["/usr/share/elasticsearch/bin/elasticsearch"]
@@ -3,3 +3,4 @@ discovery.type: "single-node"
cluster.routing.allocation.disk.threshold_enabled: false
network.bind_host: 0.0.0.0
xpack.security.enabled: false
ingest.geoip.downloader.enabled: false
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@openstapps/database",
"version": "3.0.0",
"version": "4.0.1",
"private": true,
"files": [
"config",
+24
View File
@@ -1,5 +1,29 @@
# @openstapps/proxy
## 4.0.5
### Patch Changes
- 8ccbfac0: Bumping proxy version to rebuild image
## 4.0.2
### Patch Changes
- Updated dependencies [6b06de40]
- @openstapps/logger@4.0.2
## 4.0.0
### Major Changes
- c8e29020: Update to Node 22
### Patch Changes
- Updated dependencies [c8e29020]
- @openstapps/logger@4.0.0
## 3.0.0
### Major Changes
+1 -3
View File
@@ -16,7 +16,7 @@
// ESM is not supported, and cts is not detected, so we use type-checked cjs instead.
/** @type {import('../src/common').ConfigFile} */
const configFile = {
module.exports = {
activeVersions: ['1\\.0\\.\\d+', '2\\.0\\.\\d+'],
hiddenRoutes: ['/bulk'],
logFormat: 'default',
@@ -31,5 +31,3 @@ const configFile = {
dhparam: '/etc/nginx/certs/dhparam.pem',
},
};
export default configFile;
+13 -13
View File
@@ -1,7 +1,7 @@
{
"name": "@openstapps/proxy",
"description": "NGINX proxy that is dynamically configured by a Node.js script",
"version": "3.0.0",
"version": "4.0.5",
"private": true,
"type": "module",
"license": "AGPL-3.0-only",
@@ -44,39 +44,39 @@
"@openstapps/logger": "workspace:*",
"@types/config": "3.3.0",
"@types/dockerode": "3.3.17",
"@types/node": "18.15.3",
"@types/node": "22.15.31",
"@types/sha1": "1.1.3",
"config": "3.3.9",
"dockerode": "3.3.5",
"is-cidr": "4.0.2",
"mustache": "4.2.0",
"semver": "7.3.8",
"typescript": "5.1.6"
"semver": "7.6.0",
"typescript": "5.9.3"
},
"devDependencies": {
"@openstapps/api-cli": "workspace:*",
"@openstapps/eslint-config": "workspace:*",
"@openstapps/prettier-config": "workspace:*",
"@openstapps/tsconfig": "workspace:*",
"@types/chai": "4.3.5",
"@types/chai": "4.3.20",
"@types/config": "3.3.0",
"@types/dockerode": "3.3.17",
"@types/mocha": "10.0.1",
"@types/mocha": "10.0.10",
"@types/mustache": "4.2.2",
"@types/node": "18.15.3",
"@types/node": "22.15.31",
"@types/proxyquire": "1.3.28",
"@types/semver": "7.3.13",
"@types/semver": "7.5.8",
"@types/sha1": "1.1.3",
"@types/sinon": "10.0.14",
"@types/sinon-chai": "3.2.9",
"c8": "7.14.0",
"chai": "4.3.7",
"mocha": "10.2.0",
"c8": "10.1.3",
"chai": "4.5.0",
"mocha": "10.8.2",
"mocha-junit-reporter": "2.2.0",
"sinon": "15.0.4",
"sinon-chai": "3.7.0",
"ts-node": "10.9.1",
"tsup": "6.7.0"
"ts-node": "10.9.2",
"tsup": "8.5.0"
},
"tsup": {
"entry": [
+1 -1
View File
@@ -1,4 +1,4 @@
{
"extends": "@openstapps/tsconfig",
"exclude": ["./config/", "./lib/"]
"exclude": ["config", "lib", "app.js"]
}
+14 -2
View File
@@ -1,5 +1,17 @@
# @openstapps/backend-config
## 4.0.3
### Patch Changes
- 3a274a3a: Upgrade to Capacitor 7 and Anuglar 18
## 4.0.0
### Major Changes
- c8e29020: Update to Node 22
## 3.0.0
### Major Changes
@@ -30,7 +42,7 @@
```js
#!/usr/bin/env node
import './lib/app.js';
import "./lib/app.js";
```
- 64caebaf: Migrate to ESM
@@ -105,7 +117,7 @@
```js
#!/usr/bin/env node
import './lib/app.js';
import "./lib/app.js";
```
- 64caebaf: Migrate to ESM
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@openstapps/backend-config",
"description": "Backend Configuration for OpenStApps",
"version": "3.0.0",
"version": "4.0.3",
"private": true,
"type": "module",
"license": "GPL-3.0-only",
@@ -10,7 +10,7 @@
<group title="canteen" title.de="Mensa" icon="local_cafe" route="/canteen"/>
<group title="campus map" title.de="Campus Karte" icon="map" route="/map"/>
<group title="my app" title.de="Meine App" icon="school" route="/profile">
<item title="favorites" title.de="Favoriten" icon="grade" route="/favorites"/>
<item title="favorites" title.de="Favoriten" icon="star" route="/favorites"/>
<item title="schedule" title.de="Stundenplan" icon="calendar_today" route="/schedule"/>
<item title="library account" title.de="Bibliothekskonto" icon="badge" route="/library-account" authProvider="paia"/>
<item title="settings" title.de="Einstellungen" icon="settings" route="/settings"/>
+1 -1
View File
@@ -10,7 +10,7 @@
<group title="canteen" title.de="Mensa" icon="local_cafe" route="/canteen"/>
<group title="campus map" title.de="Campus Karte" icon="map" route="/map"/>
<group title="my app" title.de="Meine App" icon="school" route="/profile">
<item title="favorites" title.de="Favoriten" icon="grade" route="/favorites"/>
<item title="favorites" title.de="Favoriten" icon="star" route="/favorites"/>
<item title="schedule" title.de="Stundenplan" icon="calendar_today" route="/schedule"/>
<item title="library account" title.de="Bibliothekskonto" icon="badge" route="/library-account" authProvider="paia"/>
<item title="settings" title.de="Einstellungen" icon="settings" route="/settings"/>
+26 -8
View File
@@ -1,5 +1,17 @@
# @openstapps/eslint-config
## 4.0.3
### Patch Changes
- 3a274a3a: Upgrade to Capacitor 7 and Anuglar 18
## 4.0.0
### Major Changes
- c8e29020: Update to Node 22
## 3.0.0
### Major Changes
@@ -30,7 +42,7 @@
```js
#!/usr/bin/env node
import './lib/app.js';
import "./lib/app.js";
```
- 64caebaf: Migrate to ESM
@@ -75,11 +87,14 @@
- 64caebaf: Migrated changelogs to changeset format
```js
import fs from 'fs';
import fs from "fs";
const path = 'packages/logger/CHANGELOG.md';
const path = "packages/logger/CHANGELOG.md";
fs.writeFileSync(path, fs.readFileSync(path, 'utf8').replace(/^#+\s+\[/gm, '## ['));
fs.writeFileSync(
path,
fs.readFileSync(path, "utf8").replace(/^#+\s+\[/gm, "## ["),
);
```
- 98546a97: Migrate away from @openstapps/configuration
@@ -122,7 +137,7 @@
```js
#!/usr/bin/env node
import './lib/app.js';
import "./lib/app.js";
```
- 64caebaf: Migrate to ESM
@@ -167,11 +182,14 @@
- 64caebaf: Migrated changelogs to changeset format
```js
import fs from 'fs';
import fs from "fs";
const path = 'packages/logger/CHANGELOG.md';
const path = "packages/logger/CHANGELOG.md";
fs.writeFileSync(path, fs.readFileSync(path, 'utf8').replace(/^#+\s+\[/gm, '## ['));
fs.writeFileSync(
path,
fs.readFileSync(path, "utf8").replace(/^#+\s+\[/gm, "## ["),
);
```
- 98546a97: Migrate away from @openstapps/configuration
@@ -1,4 +1,3 @@
// @ts-check
const fs = require("fs");
const path = require("node:path");
const child_process = require("child_process");
@@ -1,4 +1,3 @@
// @ts-check
"use strict"
const rule = require('./copyright-header-rule')
+2 -5
View File
@@ -1,5 +1,3 @@
// @ts-check
/** @type {import('eslint').Linter.Config} */
const config = {
root: true,
@@ -24,7 +22,7 @@ const config = {
'plugin:unicorn/recommended',
'prettier',
],
plugins: ['eslint-plugin-unicorn', 'eslint-plugin-jsdoc'],
plugins: ['eslint-plugin-unicorn', 'eslint-plugin-jsdoc', '@stylistic/eslint-plugin'],
settings: {
jsdoc: {
mode: 'typescript',
@@ -78,7 +76,7 @@ const config = {
],
},
],
'@stylistic/lines-between-class-members': ['error', 'always'],
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-unused-vars': [
'error',
@@ -87,7 +85,6 @@ const config = {
argsIgnorePattern: '^_',
},
],
'@typescript-eslint/lines-between-class-members': ['error', 'always'],
'@typescript-eslint/no-explicit-any': 'error',
'@typescript-eslint/no-non-null-assertion': 'off',
},
+11 -11
View File
@@ -1,7 +1,7 @@
{
"name": "@openstapps/eslint-config",
"description": "A collection of configuration base files for StApps projects. Just an (unused) experiment for now.",
"version": "3.0.0",
"version": "4.0.3",
"type": "commonjs",
"license": "GPL-3.0-only",
"repository": "git@gitlab.com:openstapps/eslint-config.git",
@@ -17,17 +17,17 @@
],
"devDependencies": {
"@openstapps/tsconfig": "workspace:*",
"@types/node": "18.15.3",
"eslint": "8.43.0",
"typescript": "5.1.6"
"@types/node": "22.15.31",
"eslint": "8.57.0",
"typescript": "5.9.3"
},
"peerDependencies": {
"@typescript-eslint/eslint-plugin": "5.60.1",
"@typescript-eslint/parser": "5.60.1",
"eslint": "8.43.0",
"eslint-config-prettier": "8.8.0",
"eslint-plugin-jsdoc": "46.4.2",
"eslint-plugin-prettier": "4.2.1",
"eslint-plugin-unicorn": "47.0.0"
"@stylistic/eslint-plugin": "5.10.0",
"@typescript-eslint/eslint-plugin": "8.39.1",
"@typescript-eslint/parser": "8.39.1",
"eslint": "8.57.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-jsdoc": "48.2.1",
"eslint-plugin-unicorn": "51.0.1"
}
}
+26 -8
View File
@@ -1,5 +1,17 @@
# @openstapps/prettier-config
## 4.0.0
### Major Changes
- c8e29020: Update to Node 22
## 3.2.0
### Patch Changes
- dbb55850: Update Prettier to 3.1.1
## 3.0.0
### Major Changes
@@ -30,7 +42,7 @@
```js
#!/usr/bin/env node
import './lib/app.js';
import "./lib/app.js";
```
- 64caebaf: Migrate to ESM
@@ -69,11 +81,14 @@
- 64caebaf: Migrated changelogs to changeset format
```js
import fs from 'fs';
import fs from "fs";
const path = 'packages/logger/CHANGELOG.md';
const path = "packages/logger/CHANGELOG.md";
fs.writeFileSync(path, fs.readFileSync(path, 'utf8').replace(/^#+\s+\[/gm, '## ['));
fs.writeFileSync(
path,
fs.readFileSync(path, "utf8").replace(/^#+\s+\[/gm, "## ["),
);
```
- 98546a97: Migrate away from @openstapps/configuration
@@ -115,7 +130,7 @@
```js
#!/usr/bin/env node
import './lib/app.js';
import "./lib/app.js";
```
- 64caebaf: Migrate to ESM
@@ -154,11 +169,14 @@
- 64caebaf: Migrated changelogs to changeset format
```js
import fs from 'fs';
import fs from "fs";
const path = 'packages/logger/CHANGELOG.md';
const path = "packages/logger/CHANGELOG.md";
fs.writeFileSync(path, fs.readFileSync(path, 'utf8').replace(/^#+\s+\[/gm, '## ['));
fs.writeFileSync(
path,
fs.readFileSync(path, "utf8").replace(/^#+\s+\[/gm, "## ["),
);
```
- 98546a97: Migrate away from @openstapps/configuration
+16
View File
@@ -0,0 +1,16 @@
/** @type {import('prettier').Config} */
const config = {
tabWidth: 2,
printWidth: 110,
useTabs: false,
semi: true,
singleQuote: true,
quoteProps: 'consistent',
trailingComma: 'all',
bracketSpacing: false,
arrowParens: 'avoid',
endOfLine: 'lf',
htmlWhitespaceSensitivity: 'strict'
}
module.exports = config;
-13
View File
@@ -1,13 +0,0 @@
{
"$schema": "http://json.schemastore.org/prettierrc",
"tabWidth": 2,
"printWidth": 110,
"useTabs": false,
"semi": true,
"singleQuote": true,
"quoteProps": "consistent",
"trailingComma": "all",
"bracketSpacing": false,
"arrowParens": "avoid",
"endOfLine": "lf"
}
+9 -6
View File
@@ -1,24 +1,27 @@
{
"name": "@openstapps/prettier-config",
"description": "StApps Prettier Config",
"version": "3.0.0",
"type": "module",
"version": "4.0.0",
"type": "commonjs",
"license": "GPL-3.0-only",
"repository": "git@gitlab.com:openstapps/prettier-config.git",
"author": "Thea Schöbl <dev@theaninova.de>",
"contributors": [
"Rainer Killinger <mail-openstapps@killinger.co>"
],
"main": "index.json",
"main": "index.js",
"files": [
"index.json",
"index.js",
"CHANGELOG.md",
"README.md"
],
"scripts": {
"test": "npx prettier --config index.json --check \"test/*.js\""
"test": "prettier --config index.js --check \"test/*.js\""
},
"devDependencies": {
"prettier": "3.1.1"
},
"peerDependencies": {
"prettier": "2.8.6"
"prettier": "3.1.1"
}
}
@@ -1,5 +1,38 @@
# @openstapps/projectmanagement
## 4.0.5
### Patch Changes
- 86004881: Updated node-glob dependency
## 4.0.2
### Patch Changes
- Updated dependencies [6b06de40]
- @openstapps/logger@4.0.2
- @openstapps/gitlab-api@4.0.2
## 4.0.1
### Patch Changes
- b40ba7ad: Updated Elasticsearch dependency
## 4.0.0
### Major Changes
- c8e29020: Update to Node 22
### Patch Changes
- Updated dependencies [c8e29020]
- @openstapps/collection-utils@4.0.0
- @openstapps/gitlab-api@4.0.0
- @openstapps/logger@4.0.0
## 3.0.0
### Major Changes
+15 -16
View File
@@ -1,7 +1,7 @@
{
"name": "@openstapps/projectmanagement",
"description": "Main documentation and scripts for maintenance.",
"version": "3.0.0",
"version": "4.0.5",
"private": true,
"type": "module",
"license": "GPL-3.0-only",
@@ -41,31 +41,30 @@
"@openstapps/collection-utils": "workspace:*",
"@openstapps/gitlab-api": "workspace:*",
"@openstapps/logger": "workspace:*",
"@slack/web-api": "6.8.1",
"commander": "10.0.0",
"date-fns": "2.30.0",
"glob": "10.2.7",
"date-fns": "3.6.0",
"glob": "10.5.0",
"mustache": "4.2.0"
},
"devDependencies": {
"@openstapps/eslint-config": "workspace:*",
"@openstapps/prettier-config": "workspace:*",
"@openstapps/tsconfig": "workspace:*",
"@types/chai": "4.3.5",
"@types/chai-as-promised": "7.1.5",
"@types/glob": "8.0.1",
"@types/mocha": "10.0.1",
"@types/chai": "4.3.20",
"@types/chai-as-promised": "7.1.8",
"@types/glob": "8.1.0",
"@types/mocha": "10.0.10",
"@types/mustache": "4.2.2",
"@types/node": "18.15.3",
"@types/node": "22.15.31",
"@types/tmp": "0.2.3",
"c8": "7.14.0",
"chai": "4.3.7",
"chai-as-promised": "7.1.1",
"mocha": "10.2.0",
"c8": "10.1.3",
"chai": "4.5.0",
"chai-as-promised": "7.1.2",
"mocha": "10.8.2",
"mocha-junit-reporter": "2.2.0",
"ts-node": "10.9.1",
"tsup": "6.7.0",
"typescript": "5.1.6"
"ts-node": "10.9.2",
"tsup": "8.5.0",
"typescript": "5.9.3"
},
"tsup": {
"entry": [
@@ -22,7 +22,6 @@ import {
User,
} from '@openstapps/gitlab-api';
import {Logger} from '@openstapps/logger';
import {WebClient} from '@slack/web-api';
import {CONCURRENCY, GROUPS, MAX_DEPTH_FOR_REMINDER, NOTE_PREFIX, SLACK_CHANNEL} from '../configuration.js';
import {mapAsyncLimit} from '@openstapps/collection-utils';
@@ -53,8 +52,7 @@ export async function remind(api: Api): Promise<void> {
Logger.info(`Found ${mergeRequests.length} open merge requests.`);
// instantiate slack client
const client =
process.env.SLACK_API_TOKEN === undefined ? undefined : new WebClient(process.env.SLACK_API_TOKEN);
const client = undefined;
// get members of the main group
const members = await api.getMembers(MembershipScope.GROUPS, GROUPS[0]);
@@ -1,3 +1,4 @@
{
"extends": "@openstapps/tsconfig"
"extends": "@openstapps/tsconfig",
"exclude": ["lib", "app.js"]
}
+14 -2
View File
@@ -1,5 +1,17 @@
# @openstapps/tsconfig
## 4.0.0
### Major Changes
- c8e29020: Update to Node 22
## 3.3.0
### Minor Changes
- 688bc5f2: v3.3.0 changes
## 3.0.0
### Major Changes
@@ -30,7 +42,7 @@
```js
#!/usr/bin/env node
import './lib/app.js';
import "./lib/app.js";
```
- 64caebaf: Migrate to ESM
@@ -105,7 +117,7 @@
```js
#!/usr/bin/env node
import './lib/app.js';
import "./lib/app.js";
```
- 64caebaf: Migrate to ESM
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@openstapps/tsconfig",
"description": "The tsconfig for the openstapps project",
"version": "3.0.0",
"version": "4.0.0",
"type": "commonjs",
"license": "GPL-3.0-only",
"repository": "git@gitlab.com:openstapps/eslint-config.git",
+11 -4
View File
@@ -14,19 +14,26 @@
"noFallthroughCasesInSwitch": true,
"isolatedModules": true,
"allowJs": true,
"checkJs": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"outDir": "../../../lib/",
"lib": ["ES2022", "DOM"],
"lib": [
"ES2022",
"DOM"
],
"strict": true,
"target": "ES2022"
},
"ts-node": {
"transpileOnly": true
},
"exclude": ["../../../app.js", "../../../lib/"]
"exclude": [
"../../../app.js",
"../../../lib/"
]
}
+1 -1
View File
@@ -9,7 +9,7 @@ const args = files.map(it => `${it.split('/', 2)[1]}='${it}'`);
console.log(
'Collecting coverage...',
await promisify(exec)(`cobertura-merge -o ./coverage.xml ${args.join(' ')}`),
await promisify(exec)(`merge-cobertura -o ./coverage.xml ${args.join(' ')}`),
);
const reportFiles = await glob('./*/*/coverage/report-junit.xml');

Some files were not shown because too many files have changed in this diff Show More