From c155face32547415d42b9fb3ef04bfbdc164977b Mon Sep 17 00:00:00 2001 From: Daniel von Atzigen Date: Wed, 8 May 2024 09:29:46 +0200 Subject: [PATCH] Deployment to int (#105) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * local development environment * relocate local development init files * create ci action * update ci action * update ci action * clean unit-tests and fix lint errors * create codeQL action * update codeQL action * create pre-release action * update pre-release action * update pre-release action * update pre-release action * update pre-release action * assets #12 setup local environment and create a clean DB * create release action * update release action * update release action * clean-up * rename development-names * update release action * update release action * update release action * update docker file * update docker file * Bump @babel/traverse from 7.20.12 to 7.24.0 Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.20.12 to 7.24.0. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.24.0/packages/babel-traverse) --- updated-dependencies: - dependency-name: "@babel/traverse" dependency-type: indirect ... Signed-off-by: dependabot[bot] * Bump webpack and @angular-devkit/build-angular Bumps [webpack](https://github.com/webpack/webpack) to 5.76.1 and updates ancestor dependency [@angular-devkit/build-angular](https://github.com/angular/angular-cli). These dependencies need to be updated together. Updates `webpack` from 5.75.0 to 5.76.1 - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.75.0...v5.76.1) Updates `@angular-devkit/build-angular` from 15.1.1 to 15.2.10 - [Release notes](https://github.com/angular/angular-cli/releases) - [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md) - [Commits](https://github.com/angular/angular-cli/compare/15.1.1...15.2.10) --- updated-dependencies: - dependency-name: webpack dependency-type: indirect - dependency-name: "@angular-devkit/build-angular" dependency-type: direct:development ... Signed-off-by: dependabot[bot] * Bump vite from 4.0.4 to 4.5.2 Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 4.0.4 to 4.5.2. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v4.5.2/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v4.5.2/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-type: direct:development ... Signed-off-by: dependabot[bot] * Bump word-wrap from 1.2.3 to 1.2.5 Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.5. - [Release notes](https://github.com/jonschlinkert/word-wrap/releases) - [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.5) --- updated-dependencies: - dependency-name: word-wrap dependency-type: indirect ... Signed-off-by: dependabot[bot] * Bump axios from 1.4.0 to 1.6.7 Bumps [axios](https://github.com/axios/axios) from 1.4.0 to 1.6.7. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v1.4.0...v1.6.7) --- updated-dependencies: - dependency-name: axios dependency-type: indirect ... Signed-off-by: dependabot[bot] * Bump follow-redirects from 1.15.2 to 1.15.5 Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.2 to 1.15.5. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.2...v1.15.5) --- updated-dependencies: - dependency-name: follow-redirects dependency-type: indirect ... Signed-off-by: dependabot[bot] * Bump undici from 5.22.1 to 5.28.3 Bumps [undici](https://github.com/nodejs/undici) from 5.22.1 to 5.28.3. - [Release notes](https://github.com/nodejs/undici/releases) - [Commits](https://github.com/nodejs/undici/compare/v5.22.1...v5.28.3) --- updated-dependencies: - dependency-name: undici dependency-type: indirect ... Signed-off-by: dependabot[bot] * Bump semver from 5.7.1 to 5.7.2 Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2. - [Release notes](https://github.com/npm/node-semver/releases) - [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md) - [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2) --- updated-dependencies: - dependency-name: semver dependency-type: indirect ... Signed-off-by: dependabot[bot] * Bump ip from 2.0.0 to 2.0.1 Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1. - [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1) --- updated-dependencies: - dependency-name: ip dependency-type: indirect ... Signed-off-by: dependabot[bot] * assets-39: remove console log of password from test * Feature/assets 16 replace logos (#43) * assets-16: replace the old logo and favicon with new ones * assets-32: replace the logo with the actual one for assets * Feature/assets 8: add missing scrollbars (#40) * assets-8: add scrollbars to all tabs in assets editor and user management * assets-8: remove some duplicate attributes * assets-8: fix unchanged files with annotations * assets-8: fix unchanged files with annotations * assets-8: fix unchanged files with annotations --------- Co-authored-by: Alex Graf * assets-32: break long titles so the edit button is not hidden. same for the search result in order to display the entire title (#44) * update pre-release action * update pre-release action * update pre-release action * update pre-release action * update release action * update release action * update dockerfiles and actions * Bump follow-redirects from 1.15.5 to 1.15.6 Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.5 to 1.15.6. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.5...v1.15.6) --- updated-dependencies: - dependency-name: follow-redirects dependency-type: indirect ... Signed-off-by: dependabot[bot] * Bump fast-xml-parser and @aws-sdk/client-s3 Bumps [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) to 4.2.5 and updates ancestor dependency [@aws-sdk/client-s3](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-s3). These dependencies need to be updated together. Updates `fast-xml-parser` from 4.0.11 to 4.2.5 - [Release notes](https://github.com/NaturalIntelligence/fast-xml-parser/releases) - [Changelog](https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/CHANGELOG.md) - [Commits](https://github.com/NaturalIntelligence/fast-xml-parser/compare/v4.0.11...v4.2.5) Updates `@aws-sdk/client-s3` from 3.252.0 to 3.537.0 - [Release notes](https://github.com/aws/aws-sdk-js-v3/releases) - [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-s3/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.537.0/clients/client-s3) --- updated-dependencies: - dependency-name: fast-xml-parser dependency-type: indirect - dependency-name: "@aws-sdk/client-s3" dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Bump tough-cookie and @cypress/request Bumps [tough-cookie](https://github.com/salesforce/tough-cookie) and [@cypress/request](https://github.com/cypress-io/request). These dependencies needed to be updated together. Updates `tough-cookie` from 4.1.2 to 4.1.3 - [Release notes](https://github.com/salesforce/tough-cookie/releases) - [Changelog](https://github.com/salesforce/tough-cookie/blob/master/CHANGELOG.md) - [Commits](https://github.com/salesforce/tough-cookie/compare/v4.1.2...v4.1.3) Updates `@cypress/request` from 2.88.11 to 2.88.12 - [Release notes](https://github.com/cypress-io/request/releases) - [Changelog](https://github.com/cypress-io/request/blob/master/CHANGELOG.md) - [Commits](https://github.com/cypress-io/request/compare/v2.88.11...v2.88.12) --- updated-dependencies: - dependency-name: tough-cookie dependency-type: indirect - dependency-name: "@cypress/request" dependency-type: indirect ... Signed-off-by: dependabot[bot] * update release action * update release action * update release action * update release action * Bump the npm_and_yarn group across 1 directory with 6 updates Bumps the npm_and_yarn group with 6 updates in the / directory: | Package | From | To | | --- | --- | --- | | [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) | `4.0.11` | `4.2.5` | | [@aws-sdk/client-s3](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-s3) | `3.252.0` | `3.537.0` | | [follow-redirects](https://github.com/follow-redirects/follow-redirects) | `1.15.5` | `1.15.6` | | [ip](https://github.com/indutny/node-ip) | `2.0.0` | `2.0.1` | | [tough-cookie](https://github.com/salesforce/tough-cookie) | `4.1.2` | `4.1.3` | | [@cypress/request](https://github.com/cypress-io/request) | `2.88.11` | `2.88.12` | Updates `fast-xml-parser` from 4.0.11 to 4.2.5 - [Release notes](https://github.com/NaturalIntelligence/fast-xml-parser/releases) - [Changelog](https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/CHANGELOG.md) - [Commits](https://github.com/NaturalIntelligence/fast-xml-parser/compare/v4.0.11...v4.2.5) Updates `@aws-sdk/client-s3` from 3.252.0 to 3.537.0 - [Release notes](https://github.com/aws/aws-sdk-js-v3/releases) - [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-s3/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.537.0/clients/client-s3) Updates `follow-redirects` from 1.15.5 to 1.15.6 - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.5...v1.15.6) Updates `ip` from 2.0.0 to 2.0.1 - [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1) Updates `tough-cookie` from 4.1.2 to 4.1.3 - [Release notes](https://github.com/salesforce/tough-cookie/releases) - [Changelog](https://github.com/salesforce/tough-cookie/blob/master/CHANGELOG.md) - [Commits](https://github.com/salesforce/tough-cookie/compare/v4.1.2...v4.1.3) Updates `@cypress/request` from 2.88.11 to 2.88.12 - [Release notes](https://github.com/cypress-io/request/releases) - [Changelog](https://github.com/cypress-io/request/blob/master/CHANGELOG.md) - [Commits](https://github.com/cypress-io/request/compare/v2.88.11...v2.88.12) --- updated-dependencies: - dependency-name: fast-xml-parser dependency-type: indirect dependency-group: npm_and_yarn-security-group - dependency-name: "@aws-sdk/client-s3" dependency-type: direct:production dependency-group: npm_and_yarn-security-group - dependency-name: follow-redirects dependency-type: indirect dependency-group: npm_and_yarn-security-group - dependency-name: ip dependency-type: indirect dependency-group: npm_and_yarn-security-group - dependency-name: tough-cookie dependency-type: indirect dependency-group: npm_and_yarn-security-group - dependency-name: "@cypress/request" dependency-type: indirect dependency-group: npm_and_yarn-security-group ... Signed-off-by: dependabot[bot] * update release action * update release action * update pre-release action * update dev-deploy action * update dev-deploy action * update dev-deploy action * update dev-deploy action * update dev-deploy action * update dev-deploy action * update dev-deploy action * update dev-deploy action * update dev-deploy action * update release action * update release action * update release action * #67: update elasticsearch-index local * fix lint * #11 fix sonar-issues, unit-tests * Feature/assets 7 eIAM (#75) #7: integrate eIAM * Add elasticsearch init script * Remove initial `rdsadmin` user * Extend setup instructions in README * update create-docker-image action * update create-docker-image action * update create-docker-image action * Replace build workflows with new unified `build` workflow * Rewrite `release` workflow to just add `latest` flag The workflow will no longer add a new image tagged as `release`. Also, the ChangeLog has been removed completely as it is not used by the current project team. * Re-add codeql workflow * Remove pull request triggers from workflows * Remove duplicates from displayed sibling assets * Remove all existing siblings when patching an asset * Revert bad commits * Remove all existing siblings when patching an asset * Add tagging/release notes to actions * Add name to `release` pipeline * Remove self-dependency of `build.build` step * Remove docker image version tag * Use `install` instead of `ci` to install node modules * Run nx with `npx` * Add node modules cache to build pipeline * Add debug steps to build pipeline * Move debug steps to test job * Add `npm ci` to check jobs * Cache build node_modules from within build dir * Reset nx in build pipeline * Add explicit typing to `contact-edit.service` * Add dev setup steps to build pipeline * Remove postinstall from build pipeline * Run `ng` via npx in build pipeline * Replace `actions/cache@v2` with `v4` * Make `tag_edge_commit` build step depend on `build_and_push_app` * Fix pipeline job branch check * Add checkouts before building images * Make GITHUB_TOKEN an input for `create-image` action * Add startup prisma migration to server Dockerfile * #81: Added checking for user groups in middleware and returns the error message to the frontend. Added env variable fields to template for o_Auth * #81: Show error message when error returned from the backend * Remove unused code for auth (password reset etc) as part of #11 * #81: pr comments and remove serach field on error page * Create Bug template * Add Issue template * Refine templates * #81: fix lint issues * Extract CRUD of `asset` table into `AssetRepo` * Install `@faker-js/faker` Library for generating fake data for testing. * Test `AssetRepo` * Apply `build` workflow to all branches * Update `fp-ts` package `tap` function is only available from 2.15+ * Extract elasticsearch usages into `AssetSearchService` * Add `AllStudy` view definition to schema * Test `AssetSearchService` * Replace elasticsearch usages by `AssetSearchService` * Merge pull request #96 from swisstopo/feature/asset-71-update-elasticsearch-index * Merge pull request #98 from swisstopo/feature/asset-33-bug-alternative-ids --------- Signed-off-by: dependabot[bot] Co-authored-by: Alex Graf Co-authored-by: till_schuetze Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Till Schütze <151851258+TIL-EBP@users.noreply.github.com> Co-authored-by: Jannic Veith <103118462+vej-ananas@users.noreply.github.com> Co-authored-by: Jannic Veith --- .editorconfig | 1 + .github/ISSUE_TEMPLATE/1-issue.md | 23 + .github/ISSUE_TEMPLATE/2-bug.md | 33 + .github/actions/create-image/action.yaml | 57 + .github/actions/deploy/action.yaml | 84 - .github/actions/generate-version/action.yaml | 15 - .github/actions/registry-push/action.yaml | 26 - .github/workflows/build.yml | 231 + .github/workflows/codeql.yml | 38 + .github/workflows/release.yml | 115 + .github/workflows/swissgeol-dev.yml | 67 - .github/workflows/swissgeol-int.yml | 100 - .github/workflows/swissgeol-prod.yml | 100 - .gitignore | 1 + .vscode/settings.json | 4 +- README.md | 189 +- apps/client-asset-sg-e2e/cypress.config.ts | 2 +- .../src/support/commands.ts | 2 +- apps/client-asset-sg/docker/Dockerfile | 5 +- apps/client-asset-sg/project.json | 193 +- .../src/app/app.component.html | 10 +- .../src/app/app.component.spec.ts | 31 - apps/client-asset-sg/src/app/app.component.ts | 86 +- apps/client-asset-sg/src/app/app.module.ts | 180 +- .../components/app-bar/app-bar.component.html | 2 +- .../components/app-bar/app-bar.component.scss | 1 + .../app/components/error/error.component.html | 6 + .../app/components/error/error.component.scss | 13 + .../app/components/error/error.component.ts | 24 + .../not-found/not-found.component.ts | 2 +- .../redirect-to-lang.component.ts | 9 +- apps/client-asset-sg/src/app/i18n/de.ts | 41 +- apps/client-asset-sg/src/app/i18n/en.ts | 41 +- apps/client-asset-sg/src/app/i18n/fr.ts | 42 +- apps/client-asset-sg/src/app/i18n/it.ts | 41 +- apps/client-asset-sg/src/app/i18n/rm.ts | 41 +- .../src/assets/email-templates/invite.html | 49 - .../src/assets/email-templates/recover.html | 45 - apps/client-asset-sg/src/assets/logo-CH.svg | 1 - .../src/assets/swissgeol_assets.svg | 92 + .../src/environments/environment.int.ts | 5 + apps/client-asset-sg/src/favicon.ico | Bin 15086 -> 9662 bytes apps/client-asset-sg/src/styles.scss | 4 + apps/server-asset-sg/.env.template | 28 +- apps/server-asset-sg/docker/Dockerfile | 19 +- apps/server-asset-sg/docker/start.sh | 4 + apps/server-asset-sg/jest.config.ts | 9 + apps/server-asset-sg/jest.setup.ts | 4 + apps/server-asset-sg/project.json | 10 +- .../src/app/admin/admin.controller.ts | 23 +- .../src/app/admin/admin.service.ts | 80 +- .../src/app/app.controller.spec.ts | 22 - .../server-asset-sg/src/app/app.controller.ts | 103 +- apps/server-asset-sg/src/app/app.module.ts | 22 +- .../src/app/app.service.spec.ts | 21 - apps/server-asset-sg/src/app/app.service.ts | 227 +- .../app/asset-edit/asset-edit.controller.ts | 81 +- .../src/app/asset-edit/asset-edit.fake.ts | 83 + .../src/app/asset-edit/asset-edit.service.ts | 438 +- .../contact-edit/contact-edit.controller.ts | 12 +- .../contact-edit/contact-edit.service.spec.ts | 107 + .../app/contact-edit/contact-edit.service.ts | 3 +- .../src/app/jwt/jwt-middleware.ts | 150 +- apps/server-asset-sg/src/app/jwt/jwt.ts | 35 +- .../oauth-config/oauth-config.controller.ts | 16 + .../migration.sql | 19 + .../src/app/prisma/schema.prisma | 1233 +- .../src/app/repos/asset.repo.spec.ts | 243 + .../src/app/repos/asset.repo.ts | 364 + .../src/app/repos/base/repo.ts | 13 + .../src/app/scripts/create-admin-user.ts | 63 - .../app/scripts/export-to-elasticsearch.ts | 320 - .../src/app/scripts/http-utils.ts | 2 +- .../app/search/asset-search-service.spec.ts | 225 + .../src/app/search/asset-search-service.ts | 339 + .../src/app/search/elastic-search-client.ts | 17 - .../src/app/search/elasticsearch.ts | 15 + .../app/search/find-assets-by-search-text.ts | 299 - .../src/app/search/find-assets-by-title.ts | 61 - .../src/app/user/models/user.ts | 23 +- .../src/app/user/user.controller.ts | 8 +- .../src/app/user/user.service.ts | 45 +- apps/server-asset-sg/tsconfig.spec.json | 4 +- deployment/.gitignore | 2 - deployment/.npmrc | 2 - deployment/Pulumi.swissgeol-asset-dev.yaml | 1 - deployment/Pulumi.swissgeol-asset-int.yaml | 32 - deployment/Pulumi.swissgeol-asset-prod.yaml | 32 - deployment/Pulumi.yaml | 3 - deployment/components/api.ts | 89 - deployment/components/app.ts | 12 - deployment/components/auth.ts | 110 - deployment/components/debug.ts | 32 - deployment/components/routing.ts | 118 - deployment/components/search.ts | 120 - deployment/components/secrets.ts | 41 - deployment/helper.ts | 11 - deployment/index.ts | 125 - deployment/package-lock.json | 2214 -- deployment/package.json | 15 - deployment/tsconfig.json | 19 - development/.env.template | 7 + development/.gitignore | 7 + development/docker-compose.test.yaml | 36 + development/docker-compose.yaml | 154 + .../images/db}/Dockerfile | 0 development/images/db/postgres-readme.md | 1 + development/init/db/01_roles.sql | 2 + development/init/db/02_dump.sql | 17244 ++++++++++++++++ development/init/elasticsearch/init.sh | 44 + .../mappings/swissgeol_asset_asset.json | 58 + development/init/oidc/oidc-mock-clients.json | 29 + development/init/oidc/oidc-mock-users.json | 76 + docker/.env | 7 - docker/create.sh | 4 - docker/docker-compose-stage-test.yaml | 15 - docker/docker-compose.yaml | 114 - docker/up-stage-test.sh | 3 - docker/up.sh | 4 - docker/volumes/db/init/00_init_postgres.sql | 7 - docker/volumes/pgadmin/config/servers.json | 20 - envs.api.json | 107 - envs.auth.json | 130 - images/bulk-ocr/.gitignore | 1 - images/bulk-ocr/Dockerfile | 14 - images/bulk-ocr/build.sh | 2 - images/bulk-ocr/docker-compose.yaml | 9 - images/bulk-ocr/flask/ocr_pipeline.py | 85 - images/bulk-ocr/flask/readme.md | 5 - images/bulk-ocr/flask/requirements.txt | 7 - images/bulk-ocr/flask/run_ocr_pipeline.py | 29 - images/bulk-ocr/flask/server.py | 136 - .../admin-page/admin-page.component.html | 8 - .../admin-page/admin-page.component.scss | 5 + .../admin-page/admin-page.component.ts | 2 - .../admin-page/admin-page.state-machine.ts | 19 +- .../user-expanded.component.html | 9 +- .../user-expanded/user-expanded.component.ts | 13 +- libs/admin/src/lib/services/admin.service.ts | 17 - libs/asset-editor/jest.config.ts | 2 +- .../asset-editor-launch.component.html | 18 +- .../asset-editor-launch.component.scss | 35 + .../asset-editor-launch.component.ts | 49 +- ...t-editor-tab-administration.component.html | 6 +- ...set-editor-tab-administration.component.ts | 4 +- .../asset-editor-tab-contacts.component.html | 4 +- .../asset-editor-tab-contacts.component.ts | 1 - .../asset-editor-tab-general.component.html | 4 +- .../asset-editor-tab-general.component.ts | 44 +- .../asset-editor-tab-page.component.scss | 2 +- .../asset-editor-tab-references.component.ts | 3 +- .../asset-editor-tab-usage.component.html | 4 +- .../asset-editor-tab-usage.component.scss | 5 + .../asset-multiselect.component.ts | 2 +- .../src/lib/services/asset-editor.service.ts | 6 +- .../src/lib/state/asset-editor.effects.ts | 2 +- .../asset-search-detail.component.html | 4 +- .../asset-search-results.component.html | 2 +- .../src/lib/models/all-study-dto.ts | 2 +- .../lib/models/client-asset-search-params.ts | 2 +- libs/auth/src/index.ts | 1 - libs/auth/src/lib/auth.module.ts | 25 +- libs/auth/src/lib/components/login/index.ts | 1 - .../lib/components/login/login.component.html | 93 - .../lib/components/login/login.component.scss | 94 - .../lib/components/login/login.component.ts | 177 - .../components/reset-password-dialog/index.ts | 1 - .../reset-password-dialog.component.html | 41 - .../reset-password-dialog.component.scss | 25 - .../reset-password-dialog.component.ts | 139 - .../components/reset-password-page/index.ts | 1 - .../reset-password-page.component.scss | 5 - .../reset-password-page.component.ts | 31 - .../set-password-dialog.component.html | 41 - .../set-password-dialog.component.scss | 26 - .../set-password-dialog.component.ts | 139 - .../lib/components/set-password-page/index.ts | 1 - .../set-password-page.component.scss | 5 - .../set-password-page.component.ts | 32 - .../auth/src/lib/services/auth.interceptor.ts | 85 +- libs/auth/src/lib/services/auth.service.ts | 138 +- .../components/button/button.component.scss | 6 +- .../drag-handle/drag-handle.component.ts | 2 +- .../ngrx-store-logger.spec.ts | 17 + .../serialize-error/serialize-error.spec.ts | 68 + libs/core/src/lib/utils/array.ts | 36 - .../lib/services/favourite.service.spec.ts | 40 + libs/ngx-kobalte/src/lib/components/tabs.ts | 5 +- libs/ngx-kobalte/tsconfig.spec.json | 3 +- .../components/profile/profile.component.ts | 4 +- libs/shared/src/lib/models/asset-usage.ts | 1 + libs/shared/src/lib/models/user.ts | 2 + package-lock.json | 8775 +++++--- package.json | 25 +- postgres-docker-image/build.sh | 3 - postgres-docker-image/postgres-readme.md | 5 - test/data/asset-format-item.ts | 169 + test/data/asset-kind-item.ts | 505 + test/data/language-items.ts | 105 + test/data/man-cat-label-item.ts | 201 + test/data/status-asset-use-item.ts | 52 + test/data/status-work-item.ts | 132 + test/setup-db.ts | 48 + tools/BatchOCR/BatchOCR.ts | 145 - tools/BatchOCR/ExractText.ts | 60 - tools/BatchOCR/decs.d.ts | 1 - tools/BatchOCR/docker-compose.yaml | 29 - tools/generators/.gitkeep | 0 tools/github/.gitignore | 1 - tools/github/export-issues.sh | 3 - tools/scripts/gdal-it | 1 - tools/scripts/ogr2ogr | 4 - tools/scripts/publish.mjs | 56 - tools/tsconfig.tools.json | 12 - 214 files changed, 28923 insertions(+), 11145 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/1-issue.md create mode 100644 .github/ISSUE_TEMPLATE/2-bug.md create mode 100644 .github/actions/create-image/action.yaml delete mode 100644 .github/actions/deploy/action.yaml delete mode 100644 .github/actions/generate-version/action.yaml delete mode 100644 .github/actions/registry-push/action.yaml create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/codeql.yml create mode 100644 .github/workflows/release.yml delete mode 100644 .github/workflows/swissgeol-dev.yml delete mode 100644 .github/workflows/swissgeol-int.yml delete mode 100644 .github/workflows/swissgeol-prod.yml delete mode 100644 apps/client-asset-sg/src/app/app.component.spec.ts create mode 100644 apps/client-asset-sg/src/app/components/error/error.component.html create mode 100644 apps/client-asset-sg/src/app/components/error/error.component.scss create mode 100644 apps/client-asset-sg/src/app/components/error/error.component.ts delete mode 100644 apps/client-asset-sg/src/assets/email-templates/invite.html delete mode 100644 apps/client-asset-sg/src/assets/email-templates/recover.html delete mode 100644 apps/client-asset-sg/src/assets/logo-CH.svg create mode 100644 apps/client-asset-sg/src/assets/swissgeol_assets.svg create mode 100644 apps/client-asset-sg/src/environments/environment.int.ts create mode 100644 apps/server-asset-sg/docker/start.sh create mode 100644 apps/server-asset-sg/jest.setup.ts delete mode 100644 apps/server-asset-sg/src/app/app.controller.spec.ts delete mode 100644 apps/server-asset-sg/src/app/app.service.spec.ts create mode 100644 apps/server-asset-sg/src/app/asset-edit/asset-edit.fake.ts create mode 100644 apps/server-asset-sg/src/app/contact-edit/contact-edit.service.spec.ts create mode 100644 apps/server-asset-sg/src/app/oauth-config/oauth-config.controller.ts create mode 100644 apps/server-asset-sg/src/app/prisma/migrations/20240318103937_update_user_schema/migration.sql create mode 100644 apps/server-asset-sg/src/app/repos/asset.repo.spec.ts create mode 100644 apps/server-asset-sg/src/app/repos/asset.repo.ts create mode 100644 apps/server-asset-sg/src/app/repos/base/repo.ts delete mode 100644 apps/server-asset-sg/src/app/scripts/create-admin-user.ts delete mode 100644 apps/server-asset-sg/src/app/scripts/export-to-elasticsearch.ts create mode 100644 apps/server-asset-sg/src/app/search/asset-search-service.spec.ts create mode 100644 apps/server-asset-sg/src/app/search/asset-search-service.ts delete mode 100644 apps/server-asset-sg/src/app/search/elastic-search-client.ts create mode 100644 apps/server-asset-sg/src/app/search/elasticsearch.ts delete mode 100644 apps/server-asset-sg/src/app/search/find-assets-by-search-text.ts delete mode 100644 apps/server-asset-sg/src/app/search/find-assets-by-title.ts delete mode 100644 deployment/.gitignore delete mode 100644 deployment/.npmrc delete mode 100644 deployment/Pulumi.swissgeol-asset-dev.yaml delete mode 100644 deployment/Pulumi.swissgeol-asset-int.yaml delete mode 100644 deployment/Pulumi.swissgeol-asset-prod.yaml delete mode 100644 deployment/Pulumi.yaml delete mode 100644 deployment/components/api.ts delete mode 100644 deployment/components/app.ts delete mode 100644 deployment/components/auth.ts delete mode 100644 deployment/components/debug.ts delete mode 100644 deployment/components/routing.ts delete mode 100644 deployment/components/search.ts delete mode 100644 deployment/components/secrets.ts delete mode 100644 deployment/helper.ts delete mode 100644 deployment/index.ts delete mode 100644 deployment/package-lock.json delete mode 100644 deployment/package.json delete mode 100644 deployment/tsconfig.json create mode 100644 development/.env.template create mode 100644 development/.gitignore create mode 100644 development/docker-compose.test.yaml create mode 100644 development/docker-compose.yaml rename {postgres-docker-image => development/images/db}/Dockerfile (100%) create mode 100644 development/images/db/postgres-readme.md create mode 100644 development/init/db/01_roles.sql create mode 100644 development/init/db/02_dump.sql create mode 100644 development/init/elasticsearch/init.sh create mode 100644 development/init/elasticsearch/mappings/swissgeol_asset_asset.json create mode 100644 development/init/oidc/oidc-mock-clients.json create mode 100644 development/init/oidc/oidc-mock-users.json delete mode 100644 docker/.env delete mode 100755 docker/create.sh delete mode 100644 docker/docker-compose-stage-test.yaml delete mode 100644 docker/docker-compose.yaml delete mode 100755 docker/up-stage-test.sh delete mode 100755 docker/up.sh delete mode 100644 docker/volumes/db/init/00_init_postgres.sql delete mode 100644 docker/volumes/pgadmin/config/servers.json delete mode 100644 envs.api.json delete mode 100644 envs.auth.json delete mode 100644 images/bulk-ocr/.gitignore delete mode 100644 images/bulk-ocr/Dockerfile delete mode 100755 images/bulk-ocr/build.sh delete mode 100644 images/bulk-ocr/docker-compose.yaml delete mode 100644 images/bulk-ocr/flask/ocr_pipeline.py delete mode 100644 images/bulk-ocr/flask/readme.md delete mode 100644 images/bulk-ocr/flask/requirements.txt delete mode 100644 images/bulk-ocr/flask/run_ocr_pipeline.py delete mode 100644 images/bulk-ocr/flask/server.py create mode 100644 libs/asset-editor/src/lib/components/asset-editor-launch/asset-editor-launch.component.scss delete mode 100644 libs/auth/src/lib/components/login/index.ts delete mode 100644 libs/auth/src/lib/components/login/login.component.html delete mode 100644 libs/auth/src/lib/components/login/login.component.scss delete mode 100644 libs/auth/src/lib/components/login/login.component.ts delete mode 100644 libs/auth/src/lib/components/reset-password-dialog/index.ts delete mode 100644 libs/auth/src/lib/components/reset-password-dialog/reset-password-dialog.component.html delete mode 100644 libs/auth/src/lib/components/reset-password-dialog/reset-password-dialog.component.scss delete mode 100644 libs/auth/src/lib/components/reset-password-dialog/reset-password-dialog.component.ts delete mode 100644 libs/auth/src/lib/components/reset-password-page/index.ts delete mode 100644 libs/auth/src/lib/components/reset-password-page/reset-password-page.component.scss delete mode 100644 libs/auth/src/lib/components/reset-password-page/reset-password-page.component.ts delete mode 100644 libs/auth/src/lib/components/set-password-dialog/set-password-dialog.component.html delete mode 100644 libs/auth/src/lib/components/set-password-dialog/set-password-dialog.component.scss delete mode 100644 libs/auth/src/lib/components/set-password-dialog/set-password-dialog.component.ts delete mode 100644 libs/auth/src/lib/components/set-password-page/index.ts delete mode 100644 libs/auth/src/lib/components/set-password-page/set-password-page.component.scss delete mode 100644 libs/auth/src/lib/components/set-password-page/set-password-page.component.ts create mode 100644 libs/core/src/lib/ngrx-store-logger/ngrx-store-logger.spec.ts create mode 100644 libs/core/src/lib/serialize-error/serialize-error.spec.ts create mode 100644 libs/favourite/src/lib/services/favourite.service.spec.ts delete mode 100755 postgres-docker-image/build.sh delete mode 100644 postgres-docker-image/postgres-readme.md create mode 100644 test/data/asset-format-item.ts create mode 100644 test/data/asset-kind-item.ts create mode 100644 test/data/language-items.ts create mode 100644 test/data/man-cat-label-item.ts create mode 100644 test/data/status-asset-use-item.ts create mode 100644 test/data/status-work-item.ts create mode 100644 test/setup-db.ts delete mode 100644 tools/BatchOCR/BatchOCR.ts delete mode 100644 tools/BatchOCR/ExractText.ts delete mode 100644 tools/BatchOCR/decs.d.ts delete mode 100644 tools/BatchOCR/docker-compose.yaml delete mode 100644 tools/generators/.gitkeep delete mode 100644 tools/github/.gitignore delete mode 100755 tools/github/export-issues.sh delete mode 100755 tools/scripts/gdal-it delete mode 100755 tools/scripts/ogr2ogr delete mode 100644 tools/scripts/publish.mjs delete mode 100644 tools/tsconfig.tools.json diff --git a/.editorconfig b/.editorconfig index 71cd14e9..aa5b9729 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,6 +7,7 @@ indent_style = space indent_size = 2 insert_final_newline = true trim_trailing_whitespace = true +end_of_line = lf [*.md] max_line_length = off diff --git a/.github/ISSUE_TEMPLATE/1-issue.md b/.github/ISSUE_TEMPLATE/1-issue.md new file mode 100644 index 00000000..b22f1e61 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1-issue.md @@ -0,0 +1,23 @@ +--- +name: Issue +about: Beschreibe eine neue Aufgabe +title: '' +labels: '' +assignees: '' + +--- + +**Beschreibung** + +Eine klare und präzise Beschreibung der Ausgangssituation, der Problematik sowie bereits bekannter Lösungsansätze. + + + +**Abgrenzung** + +Nicht beachtet in dieser Aufgabe wird die Suche nach der Frage. + +**Acceptance Criteria** + + - [ ] Die Antwort muss 42 sein. + - [ ] ... diff --git a/.github/ISSUE_TEMPLATE/2-bug.md b/.github/ISSUE_TEMPLATE/2-bug.md new file mode 100644 index 00000000..21936a17 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2-bug.md @@ -0,0 +1,33 @@ +--- +name: Bug +about: Melde einen neuen Bug +title: 'Bug: ' +labels: bug +assignees: '' + +--- + +**Beschreibung** +Eine klare und präzise Beschreibung des Problems. + +**Schritte zum Reproduzieren** +1. Gehe zur Seite '....' +2. Klicke auf '....' +3. Scrolle zu '....' +4. Ein Fehler erscheint + +**Beobachtetes Verhalten** +Eine Beschreibung des Fehlverhaltens. + +**Erwartetes Verhalten** +Eine Beschreibung des eigentlich erwarteten Verhaltens + +**Screenshots** +Zeige Screenshots, wenn vorhanden und hilfreich. + +**Plattform** +Falls relevant: + - Device: [e.g. Desktop, iPhone6] + - OS: [e.g. Windows, iOS8.1] + - Browser [e.g. firefox, edge] + - Mobile Version [e.g. 22] diff --git a/.github/actions/create-image/action.yaml b/.github/actions/create-image/action.yaml new file mode 100644 index 00000000..62955900 --- /dev/null +++ b/.github/actions/create-image/action.yaml @@ -0,0 +1,57 @@ +name: 'create docker image' +description: 'Builds a docker image and tags it' +inputs: + IMAGE_NAME: + description: 'The image name' + required: true + TAG: + description: 'The version of the image' + required: true + DOCKERFILE: + description: 'The path to the Dockerfile' + required: true + GITHUB_TOKEN: + description: 'The github token' + required: true + +runs: + using: 'composite' + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set environment variables + shell: bash + run: | + echo COMMITED_AT=$(git show -s --format=%cI ${{ github.sha }}) >> $GITHUB_ENV + echo REVISION=$(git rev-parse --short HEAD) >> $GITHUB_ENV + + - name: Collect docker image metadata + id: meta-data + uses: docker/metadata-action@v5 + with: + images: ${{ inputs.IMAGE_NAME }} + labels: | + org.opencontainers.image.created=${{ env.COMMITED_AT }} + org.opencontainers.image.maintainer=EBP Schweiz AG + flavor: | + latest=false + tags: | + ${{ inputs.TAG }} + + - name: Log in to the GitHub container registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ inputs.GITHUB_TOKEN }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: ./ + file: ${{ inputs.DOCKERFILE }} + push: true + tags: ${{ steps.meta-data.outputs.tags }} + labels: ${{ steps.meta-data.outputs.labels }} + no-cache: true diff --git a/.github/actions/deploy/action.yaml b/.github/actions/deploy/action.yaml deleted file mode 100644 index 30d4f921..00000000 --- a/.github/actions/deploy/action.yaml +++ /dev/null @@ -1,84 +0,0 @@ -name: "Pulumi deployment to cluster" -description: "Starts a pulumi deployment to the cluster" -inputs: - # secrets for login etc - pulumiConfigSecret: - description: "Pulumi config secret" - required: true - npmPkgToken: - description: "token for npm pkg access" - required: true - awsAccessKeyId: - description: "AWS access key id" - required: true - awsSecretAccessKey: - description: "AWS secret access key" - required: true - eksClusterName: - description: "AWS EKS cluster name" - required: true - eksRoleArn: - description: "AWS EKS Role ARN" - required: true - # variables for pulumi setup - pulumiConfigPassphrase: - description: "Pulumi config passphrase" - required: true - stack: - description: "Pulumi stack name" - required: true - command: - description: "Pulumi command to run" - required: false - default: "preview" - region: - description: "AWS region" - required: false - default: "eu-central-1" - s3Bucket: - description: "S3 bucket for pulumi state" - required: false - default: "swissgeol-assets-swisstopo" - version: - description: "App version for assets" - required: false - default: "dev" -runs: - using: "composite" - steps: - # https://github.com/marketplace/actions/configure-aws-credentials-for-github-actions - - name: configure aws credentials - uses: aws-actions/configure-aws-credentials@v2 - with: - aws-access-key-id: ${{ inputs.awsAccessKeyId }} - aws-secret-access-key: ${{ inputs.awsSecretAccessKey }} - aws-region: ${{ inputs.region }} - - - name: Create kubeconfig - shell: bash - working-directory: ./deployment - run: | - aws --region ${{ inputs.region }} eks update-kubeconfig --name ${{ inputs.eksClusterName }} --alias swissgeol-${{ inputs.eksClusterName }} --role-arn ${{ inputs.eksRoleArn }} - kubectl get namespaces - - - name: install pulumi deps - shell: bash - working-directory: ./deployment - run: | - echo "//npm.pkg.github.com/:_authToken=${{ inputs.npmPkgToken }}" >> .npmrc - npm ci - - # https://github.com/marketplace/actions/pulumi-cli-action - - name: execute pulumi - uses: pulumi/actions@v4 - with: - command: ${{ inputs.command }} - stack-name: ${{ inputs.stack }} - cloud-url: "s3://${{ inputs.s3Bucket }}?region=${{ inputs.region }}&awssdk=v2" - work-dir: ./deployment - config-map: "{ geoadmin-swissgeol-asset:version: {value: ${{ inputs.version }}, secret: false }}" - env: - AWS_ACCESS_KEY_ID: ${{ inputs.awsAccessKeyId }} - AWS_SECRET_ACCESS_KEY: ${{ inputs.awsSecretAccessKey }} - AWS_REGION: ${{ inputs.region }} - PULUMI_CONFIG_PASSPHRASE: ${{ inputs.pulumiConfigPassphrase }} diff --git a/.github/actions/generate-version/action.yaml b/.github/actions/generate-version/action.yaml deleted file mode 100644 index 952f52dc..00000000 --- a/.github/actions/generate-version/action.yaml +++ /dev/null @@ -1,15 +0,0 @@ -name: "Generate Version for Asset" -description: "Generates a new version from git sha" -inputs: - path: - description: "path for version.json" - required: true -runs: - using: "composite" - steps: - - name: generate version.json - shell: bash - run: | - VERSION="{\"tag\": \"generated_by_build\",\"build\": \"${{github.run_number}}\",\"commit\": \"${{github.sha}}\"}" - echo $VERSION > ${{ inputs.path }}/version.json - cat ${{ inputs.path }}/version.json diff --git a/.github/actions/registry-push/action.yaml b/.github/actions/registry-push/action.yaml deleted file mode 100644 index 4ea0ab86..00000000 --- a/.github/actions/registry-push/action.yaml +++ /dev/null @@ -1,26 +0,0 @@ -name: "Container regsistry login & push" -description: "Logins to the registry and pushes the given images" -inputs: - image: - description: "Container image name" - required: true - username: - description: "Username for the registry" - required: true - password: - description: "Password for the registry" - required: true -runs: - using: "composite" - steps: - # https://github.com/marketplace/actions/docker-login - - name: Login to container registry - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ inputs.username }} - password: ${{ inputs.password }} - - - name: Push container image - shell: bash - run: docker push ${{ inputs.image }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..8d1d36af --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,231 @@ +name: build + +on: + push: + branches: + - '**' + workflow_dispatch: + +env: + NODE_VERSION: '20.x' + +jobs: + install: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + - name: Cache node modules + uses: actions/cache@v4 + with: + path: ./node_modules + key: "${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}" + restore-keys: | + ${{ runner.os }}-npm- + - name: Install node dependencies + run: npm ci + - name: Run postinstall + run: npm run postinstall + - name: Generate prisma types + run: | + cd apps/server-asset-sg/ + npx ng gen-prisma-client + + test: + runs-on: ubuntu-latest + needs: install + env: + DB_USERNAME: postgres-test + DB_PASSWORD: postgres-test + DB_DATABASE: postgres-test + DATABASE_URL: postgres://postgres-test:postgres-test@localhost:5432/postgres-test?schema=public + services: + db: + image: postgis/postgis + ports: + - '5432:5432' + env: + POSTGRES_USER: ${{ env.DB_USERNAME }} + POSTGRES_PASSWORD: ${{ env.DB_PASSWORD }} + POSTGRES_DB: ${{ env.DB_DATABASE }} + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + elasticsearch: + image: docker.elastic.co/elasticsearch/elasticsearch:8.12.1 + ports: + - '9200:9200' + env: + ES_JAVA_OPTS: -Xms512m -Xmx512m + xpack.security.enabled: false + discovery.type: single-node + cluster.routing.allocation.disk.threshold_enabled: false + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + - name: Restore cached node modules + uses: actions/cache@v4 + with: + path: ./node_modules + key: "${{ runner.os }}-npm-${{ steps.cache-node-modules.outputs.cache-key }}" + - name: Migrate database + run: | + cd apps/server-asset-sg/ + npx prisma migrate deploy --schema src/app/prisma/schema.prisma + - name: Run tests + run: npm run test + + lint: + runs-on: ubuntu-latest + needs: install + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + - name: Restore cached node modules + uses: actions/cache@v4 + with: + path: ./node_modules + key: "${{ runner.os }}-npm-${{ steps.cache-node-modules.outputs.cache-key }}" + - name: Run lint + run: npm run lint + + # It would be cleaner and probably more performant to replace this build step + # with either a non-emitting build or a simple type check. + # We only have `build` available for now, + # since the project is currently split across a multitude of small packages, + # all of which have to specify their own commands. + # (Daniel von Atzigen, 2024-04-12) + build: + runs-on: ubuntu-latest + needs: + - test + - lint + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + - name: Restore cached node modules + uses: actions/cache@v4 + with: + path: ./node_modules + key: "${{ runner.os }}-npm-${{ steps.cache-node-modules.outputs.cache-key }}" + - name: Reset nx + run: npx nx reset + - name: Run build + run: npm run build + + build_and_push_app: + name: 'build and push app' + if: github.event_name == 'push' && github.ref == 'refs/heads/develop' + needs: + - build + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Create image + uses: ./.github/actions/create-image + with: + IMAGE_NAME: ${{ vars.BASE_IMAGE_NAME }}-app + TAG: edge + DOCKERFILE: ./apps/client-asset-sg/docker/Dockerfile + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + build_and_push_api: + name: 'build and push api' + if: github.event_name == 'push' && github.ref == 'refs/heads/develop' + needs: + - build + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Create image + uses: ./.github/actions/create-image + with: + IMAGE_NAME: ${{ vars.BASE_IMAGE_NAME }}-api + TAG: edge + DOCKERFILE: ./apps/server-asset-sg/docker/Dockerfile + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + tag_edge_commit: + name: 'tag edge commit' + needs: + - build_and_push_app + - build_and_push_api + runs-on: ubuntu-latest + steps: + - name: Create/update tag + uses: actions/github-script@v7 + with: + script: | + github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: 'refs/tags/edge', + sha: context.sha + }).catch(err => { + if (err.status !== 422) throw err; + github.rest.git.updateRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: 'tags/edge', + sha: context.sha + }); + }) + + tag_rc_image: + name: tag rc image + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + needs: + - build + runs-on: ubuntu-latest + steps: + - name: Login to GitHub Packages + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin + + - name: Pull docker image + run: docker pull ${{ vars.BASE_IMAGE_NAME }}-app:edge + + - name: Tag docker image + run: docker tag ${{ vars.BASE_IMAGE_NAME }}-app:edge ${{ vars.BASE_IMAGE_NAME }}-app:release-candidate + + - name: Push docker image + run: docker push ${{ vars.BASE_IMAGE_NAME }}-app:release-candidate + + tag_rc_commit: + name: 'tag rc commit' + needs: tag_rc_image + runs-on: ubuntu-latest + steps: + - name: Create/update tag + uses: actions/github-script@v7 + with: + script: | + github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: 'refs/tags/release-candidate', + sha: context.sha + }).catch(err => { + if (err.status !== 422) throw err; + github.rest.git.updateRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: 'tags/release-candidate', + sha: context.sha + }); + }) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..6440b54c --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,38 @@ +name: code-ql + +on: + push: + branches: + - develop + workflow_dispatch: + schedule: + - cron: '35 4 * * 5' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'javascript' ] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..1667602b --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,115 @@ +name: release + +on: + workflow_dispatch: + inputs: + version: + description: "Version number (e.g. 1.12)" + required: true +jobs: + release_app: + name: release app + needs: + - read_version + runs-on: ubuntu-latest + steps: + - name: Login to GitHub Packages + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin + + - name: Pull docker image + run: docker pull ${{ vars.BASE_IMAGE_NAME }}-app:release-candidate + + - name: Tag docker image + run: | + docker tag ${{ vars.BASE_IMAGE_NAME }}-app:release-candidate ${{ vars.BASE_IMAGE_NAME }}-app:${{ inputs.VERSION }} + docker tag ${{ vars.BASE_IMAGE_NAME }}-app:release-candidate ${{ vars.BASE_IMAGE_NAME }}-app:latest + + - name: Push docker image + run: | + docker push ${{ vars.BASE_IMAGE_NAME }}-app:${{ inputs.VERSION }} + docker push ${{ vars.BASE_IMAGE_NAME }}-app:latest + + release_api: + name: release api + needs: + - read_version + runs-on: ubuntu-latest + steps: + - name: Login to GitHub Packages + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin + + - name: Pull docker image + run: docker pull ${{ vars.BASE_IMAGE_NAME }}-api:release-candidate + + - name: Tag docker image + run: | + docker tag ${{ vars.BASE_IMAGE_NAME }}-api:release-candidate ${{ vars.BASE_IMAGE_NAME }}-api:${{ inputs.VERSION }} + docker tag ${{ vars.BASE_IMAGE_NAME }}-api:release-candidate ${{ vars.BASE_IMAGE_NAME }}-api:latest + + - name: Push docker image + run: | + docker push ${{ vars.BASE_IMAGE_NAME }}-api:${{ inputs.VERSION }} + docker push ${{ vars.BASE_IMAGE_NAME }}-api:latest + + + tag_commit: + name: 'tag commit' + needs: + - release_app + - release_api + runs-on: ubuntu-latest + steps: + - name: Create/update latest tag + uses: actions/github-script@v7 + with: + script: | + github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: 'refs/tags/latest', + sha: context.sha + }).catch(err => { + if (err.status !== 422) throw err; + github.rest.git.updateRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: 'tags/latest', + sha: context.sha + }); + }) + + - name: Create/update version tag + uses: actions/github-script@v7 + with: + script: | + github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: 'refs/tags/${{ inputs.VERSION }}', + sha: context.sha + }).catch(err => { + if (err.status !== 422) throw err; + github.rest.git.updateRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: 'tags/${{ inputs.VERSION }}', + sha: context.sha + }); + }) + + create_release: + name: 'create release' + needs: + - release_app + - release_api + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Create release + uses: softprops/action-gh-release@v2 + with: + tag_name: '${{ inputs.VERSION }}' + name: 'swissgeol-assets v${{ inputs.VERSION }}' + generate_release_notes: true + make_latest: true diff --git a/.github/workflows/swissgeol-dev.yml b/.github/workflows/swissgeol-dev.yml deleted file mode 100644 index 6133b3b0..00000000 --- a/.github/workflows/swissgeol-dev.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: Swissgeol Asset Dev Deploy - -on: - push: - branches: ["main"] - workflow_dispatch: -env: - APP_IMAGE: ghcr.io/geoadmin/swissgeol-asset-app:dev - API_IMAGE: ghcr.io/geoadmin/swissgeol-asset-api:dev - -jobs: - # ------------------ - build-web-app: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 18 - - - name: generate version.json - id: generate-version - uses: ./.github/actions/generate-version - with: - path: ./apps/client-asset-sg/src/assets - - - name: Build app Docker image - run: docker build . -f ./apps/client-asset-sg/docker/Dockerfile -t ${{ env.APP_IMAGE }} - - - name: Push container image - id: registry-push - uses: ./.github/actions/registry-push - with: - image: ${{ env.APP_IMAGE }} - username: ${{ vars.SWISSGEOL_BUILD_USERNAME }} - password: ${{ secrets.SWISSGEOL_BUILD_PAT }} - - # ------------------ - build-web-api: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 18 - - - name: generate version.json - id: generate-version - uses: ./.github/actions/generate-version - with: - path: ./apps/server-asset-sg/src/assets - - - name: Run NPM build - run: | - npm ci - npm run build -- server-asset-sg - - name: Retag Image - working-directory: ./apps/server-asset-sg/docker - run: docker tag registry.lambda-it.ch/asset-swissgeol/api:latest ${{ env.API_IMAGE }} - - - name: Push container image - id: registry-push - uses: ./.github/actions/registry-push - with: - image: ${{ env.API_IMAGE }} - username: ${{ vars.SWISSGEOL_BUILD_USERNAME }} - password: ${{ secrets.SWISSGEOL_BUILD_PAT }} diff --git a/.github/workflows/swissgeol-int.yml b/.github/workflows/swissgeol-int.yml deleted file mode 100644 index 4294496b..00000000 --- a/.github/workflows/swissgeol-int.yml +++ /dev/null @@ -1,100 +0,0 @@ -name: Swissgeol Asset Int Deploy - -on: - release: - types: [published] - workflow_dispatch: - inputs: - tag: - description: "Container Tag" -env: - APP_IMAGE: ghcr.io/geoadmin/swissgeol-asset-app:${{ github.event.inputs.tag || github.event.release.tag_name }} - API_IMAGE: ghcr.io/geoadmin/swissgeol-asset-api:${{ github.event.inputs.tag || github.event.release.tag_name }} - -jobs: - # ------------------ - build-web-app: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - ref: ${{ github.event.release.tag_name }} - - uses: actions/setup-node@v3 - with: - node-version: 18 - - - name: generate version.json - id: generate-version - uses: ./.github/actions/generate-version - with: - path: ./apps/client-asset-sg/src/assets - - - name: Build app Docker image - run: docker build . -f ./apps/client-asset-sg/docker/Dockerfile -t ${{ env.APP_IMAGE }} - - - name: Push container image - id: registry-push - uses: ./.github/actions/registry-push - with: - image: ${{ env.APP_IMAGE }} - username: ${{ vars.SWISSGEOL_BUILD_USERNAME }} - password: ${{ secrets.SWISSGEOL_BUILD_PAT }} - - # ------------------ - build-web-api: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - ref: ${{ github.event.release.tag_name }} - - uses: actions/setup-node@v3 - with: - node-version: 18 - - - name: generate version.json - id: generate-version - uses: ./.github/actions/generate-version - with: - path: ./apps/client-asset-sg/src/assets - - - name: Run NPM build - run: | - npm ci - npm run build -- server-asset-sg - - name: Retag Image - working-directory: ./apps/server-asset-sg/docker - run: docker tag registry.lambda-it.ch/asset-swissgeol/api:latest ${{ env.API_IMAGE }} - - - name: Push container image - id: registry-push - uses: ./.github/actions/registry-push - with: - image: ${{ env.API_IMAGE }} - username: ${{ vars.SWISSGEOL_BUILD_USERNAME }} - password: ${{ secrets.SWISSGEOL_BUILD_PAT }} - - # ------------------ - deployment: - runs-on: ubuntu-latest - needs: [build-web-app, build-web-api] - steps: - - uses: actions/checkout@v3 - with: - ref: ${{ github.event.release.tag_name }} - - uses: actions/setup-node@v3 - with: - node-version: 18 - - - name: Pulumi deployment to cluster - uses: ./.github/actions/deploy - with: - pulumiConfigSecret: ${{ secrets.PULUMI_CONFIG_PASSPHRASE }} - awsAccessKeyId: ${{ secrets.AWS_ACCESS_KEY_ID }} - awsSecretAccessKey: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - eksClusterName: int - eksRoleArn: arn:aws:iam::779726271945:role/kubernetes-admins-int - pulumiConfigPassphrase: ${{ secrets.PULUMI_CONFIG_PASSPHRASE }} - stack: swissgeol-asset-int - npmPkgToken: ${{ secrets.SWISSGEOL_BUILD_PAT }} - command: up - version: ${{ github.event.release.tag_name }} diff --git a/.github/workflows/swissgeol-prod.yml b/.github/workflows/swissgeol-prod.yml deleted file mode 100644 index 4528d5fc..00000000 --- a/.github/workflows/swissgeol-prod.yml +++ /dev/null @@ -1,100 +0,0 @@ -name: Swissgeol Asset Prod Deploy - -on: - release: - types: [published] - workflow_dispatch: - inputs: - tag: - description: "Container Tag" -env: - APP_IMAGE: ghcr.io/geoadmin/swissgeol-asset-app:${{ github.event.inputs.tag || github.event.release.tag_name }} - API_IMAGE: ghcr.io/geoadmin/swissgeol-asset-api:${{ github.event.inputs.tag || github.event.release.tag_name }} - -jobs: - # ------------------ - build-web-app: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - ref: ${{ github.event.release.tag_name }} - - uses: actions/setup-node@v3 - with: - node-version: 18 - - - name: generate version.json - id: generate-version - uses: ./.github/actions/generate-version - with: - path: ./apps/client-asset-sg/src/assets - - - name: Build app Docker image - run: docker build . -f ./apps/client-asset-sg/docker/Dockerfile -t ${{ env.APP_IMAGE }} - - - name: Push container image - id: registry-push - uses: ./.github/actions/registry-push - with: - image: ${{ env.APP_IMAGE }} - username: ${{ vars.SWISSGEOL_BUILD_USERNAME }} - password: ${{ secrets.SWISSGEOL_BUILD_PAT }} - - # ------------------ - build-web-api: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - ref: ${{ github.event.release.tag_name }} - - uses: actions/setup-node@v3 - with: - node-version: 18 - - - name: generate version.json - id: generate-version - uses: ./.github/actions/generate-version - with: - path: ./apps/client-asset-sg/src/assets - - - name: Run NPM build - run: | - npm ci - npm run build -- server-asset-sg - - name: Retag Image - working-directory: ./apps/server-asset-sg/docker - run: docker tag registry.lambda-it.ch/asset-swissgeol/api:latest ${{ env.API_IMAGE }} - - - name: Push container image - id: registry-push - uses: ./.github/actions/registry-push - with: - image: ${{ env.API_IMAGE }} - username: ${{ vars.SWISSGEOL_BUILD_USERNAME }} - password: ${{ secrets.SWISSGEOL_BUILD_PAT }} - - # ------------------ - deployment: - runs-on: ubuntu-latest - needs: [build-web-app, build-web-api] - steps: - - uses: actions/checkout@v3 - with: - ref: ${{ github.event.release.tag_name }} - - uses: actions/setup-node@v3 - with: - node-version: 18 - - - name: Pulumi deployment to cluster - uses: ./.github/actions/deploy - with: - pulumiConfigSecret: ${{ secrets.PULUMI_CONFIG_PASSPHRASE }} - awsAccessKeyId: ${{ secrets.AWS_ACCESS_KEY_ID }} - awsSecretAccessKey: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - eksClusterName: prod - eksRoleArn: arn:aws:iam::779726271945:role/kubernetes-admins-prod - pulumiConfigPassphrase: ${{ secrets.PULUMI_CONFIG_PASSPHRASE }} - stack: swissgeol-asset-prod - npmPkgToken: ${{ secrets.SWISSGEOL_BUILD_PAT }} - command: up - version: ${{ github.event.release.tag_name }} diff --git a/.gitignore b/.gitignore index c04fa8be..1c03120f 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,7 @@ Thumbs.db __pycache__ +.env.local .env.staging .env.prod diff --git a/.vscode/settings.json b/.vscode/settings.json index 34d8f2e1..db0ada5d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,7 @@ { "editor.codeActionsOnSave": { - "source.organizeImports": false, - "source.fixAll.eslint": true + "source.organizeImports": "never", + "source.fixAll.eslint": "explicit" }, "peacock.color": "#0b7285", "peacock.remoteColor": "#000", diff --git a/README.md b/README.md index 7582a80f..17303b39 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,185 @@ -# asset-swissgeol-ch +# SwissGeol Asset -More docs for asset-swissgeol-ch: https://github.com/Lambda-IT/asset-swissgeol-ch/wiki +## Development +The following components must be installed on the development computer: -## Instances +✔️ Git +✔️ Docker +✔️ Node.js 20 LTS -- assets.swissgeol.ch - - assets.swissgeol.ch/kibana -- int-assets.swissgeol.ch - - int-assets.swissgeol.ch/kibana +### Setting Up the Development Environment +Follow these steps to set up the development environment on your local machine: +* [1. Configure Local Systems](#1-Configure-Local-Systems) +* [2. Configure the Asset Server](#2-Configure-the-Asset-Server) +* [3. Install Dependencies](#3-Install-Dependencies) +* [4. Build Local Systems](#4-Build-Local-Systems) +* [5. Initialize MinIO](#5-Initialize-MinIO) + +#### 1. Configure Local Systems +Configure `development/.env` according to the [development services configuration](#Development-Services-Configuration). + +#### 2. Configure the Asset Server +Create an empty copy of the [web server configuration](#Asset-Server-Configuration) as [`apps/server-asset-sg/.env.local`](apps/server-asset-sg/.env.local). +Configure the following variables: +* Set `AUTH_URL=http://localhost:8866`. +* Set `FRONTEND_URL=http://localhost:4200`. +* Set `DATABASE_URL=postgres://asset-swissgeol:asset-swissgeol@localhost:5432/postgres?schema=public`. +* Set `GOTRUE_JWT_SECRET` to the same value as in [`development/.env`](development/.env). +* Leave `OCR_URL` empty. +* Leave `OCR_CALLBACK_URL` empty. + +#### 3. Install Dependencies +Install node modules: +```bash +npm run install +``` + +Decorate the Angular CLI with the Nx CLI: +```bash +npm run postinstall +``` + +#### 4. Build Local Services +Generate prisma-client for database-access: +```bash +cd apps/server-asset-sg/ +ng gen-prisma-client +``` + +Build postgis-gotrue docker image: +```bash +cd development/images/db +docker build -t postgis-gotrue . +``` + +#### 5. Initialize MinIO +* [Start the development services](#Starting-the-Development-Environment). +* Open http://localhost:9001 +* Sign in using the `STORAGE_USER` and `STORAGE_PASSWORD` of your development environment. +* Navigate to [Buckets](http://localhost:9001/buckets) and create a new bucket with the name `asset-sg`. +* Navigate to [the new bucket's browser](http://localhost:9001/browser/asset-sg) and create an empty folder with the name `asset-sg`. +* Navigate to [Configuration](http://localhost:9001/settings/configurations/region) and change the server region to `local`. +* Navigate to [Access Keys](http://localhost:9001/access-keys) and create a new access key. +* Open your Asset Server Configuration at [`apps/server-asset-sg/.env.local`](apps/server-asset-sg/.env.local) and make the following changes: + * `S3_REGION=local` + * `S3_ENDPOINT=http://localhost:9000` + * `S3_BUCKET_NAME=asset-sg` + * `S3_ASSET_FOLDER=asset-sg` + * `S3_ACCESS_KEY_ID` as your newly generated access key. + * `S3_SECRET_ACCESS_KEY` as your newly generated access key's secret. + +### Starting the Development Environment +Start development services: +```bash +cd development +docker compose up +``` +Start the application: +```bash +npm run start +``` + +### Local Services and Applications +| 🔖App/Service | 🔗Link | 🧞User | 🔐Password | +|:-------------------------|:-------------------------------------------------|:-------------------------|:-------------------------| +| Assets (client) | [localhost:4200](http://localhost:4200/) | `admin@swissgeol.assets` | `swissgeol_assets` | +| Assets REST API (server) | [localhost:3333/api/](http://localhost:3333/api) | n/a | n/a | +| postgreSQL (docker) | localhost:5432 | .env `$DB_USER` | .env `$DB_PASSWORD` | +| Elasticsearch (docker) | [localhost:9200](http://localhost:9200) | n/a | n/a | +| Kibana (docker) | [localhost:5601](http://localhost:5601) | n/a | n/a | +| pgAdmin (docker) | [localhost:5051](http://localhost:5051/) | .env `$PGADMIN_EMAIL` | .env `$PGADMIN_PASSWORD` | +| MinIO (docker) | [localhost:9001](http://localhost:9001/) | .env `$STORAGE_USER` | .env `$STORAGE_PASSWORD` | +| smtp4dev (docker) | [localhost:5000](http://localhost:5000/) | n/a | n/a | +| oidc-server (docker) | [localhost:4011](http://localhost:4011/) | n/a | n/a | + +### Importing Example Data +You can dump data from a remote environment into a local file so you can initialize your development database with it. +To do so, use the following commands. +Be aware that you need to manually insert the `{DB_*}` values beforehand. +```bash +cd development +docker compose exec db sh -c 'pg_dump --dbname=postgresql://{DB_USERNAME}:{DB_PASSWORD}@{DB_HOST}:5432/{DB_DATABASE} --data-only --exclude-table asset_user -n public > /dump.sql' +``` +> The export will output warnings related to circular foreign-key constraints. +> These can be safely ignored. + +> The export will only contain the database's data, not its structure. +> Data related to the authentication process is also excluded, +> so we don't run into conflicts when using a different eIAM provider. + +To import the dumped data, run the following commands. +Ensure to start your database service beforehand. +```bash +# Reset the database: +npm run prisma -- migrate reset -f +npm run prisma -- migrate deploy + +# Import example data: +cd development +docker compose exec db sh -c 'psql --dbname=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB} -f /dump.sql' +``` +> You will need to manually sync the data to Elasticsearch via the admin panel in the web UI. + +## Testing +> Tests execute automatically on every push to the Git repository. + +The local tests require a running instance of both _postgreSQL_ and _Elasticsearch_. +Make sure that your local development environment is fully shutdown and then run the test services: +```bash +cd development +docker compose down +docker compose -f docker-compose.test.yml up +``` +Then run all tests: +```bash +npm run test +``` +It is also possible to run only specific tests: +```bash +# Run only the server tests: +nx run server-asset-sg:test + +# Run only a specific test suite: +nx run server-asset-sg:test -t 'AssetRepo' + +# Run only a specific, nested test suite: +nx run server-asset-sg:test -t 'AssetRepo create' +``` + +## Configuration +### Asset Server Configuration +The file `apps/server-asset-sg/.env.local` configures secrets for the SwissGeol Asset server. +An empty template for the file can be found in [`apps/server-asset-sg/.env.template`](apps/server-asset-sg/.env.template). + +| Variable | Example | Description | +|----------------------|--------------------------------------------------------------------------------------------|------------------------------------------------------------| +| AUTH_URL | http://my.gotrue.example:8866 | URL of the GoTrue auth service. | +| FRONTEND_URL | http://assets.geo.admin.ch | Public URL of the SwissGeol Asset web client. | +| S3_REGION | euw-3 | Region of the S3 instance. | +| S3_ENDPOINT | http://compute-1.amazonaws.com | URL to the S3 instance. | +| S3_ACCESS_KEY_ID | AP6wpeXraSc0IH4d42IN | Access Key for the S3 instance. | +| S3_SECRET_ACCESS_KEY | fSx5Bfib0OeAyG1mwtslKA04Qj6oPStLcpnkACmF | Secret Key for the S3 instance. | +| S3_BUCKET_NAME | asset-sg | S3 bucket name. | +| S3_ASSET_FOLDER | asset-sg | Folder within the S3 bucket into which objects are stored. | +| DATABASE_URL | postgres://asset-swissgeol:asset-swissgeol@my.postgres.example:5432/postgres?schema=public | PostgreSQL access URL. | +| GOTRUE_JWT_SECRET | 18af41574b30be7539d8c3e45ccdeea9431cff6419cdce5cabc5f28cfb73e15c | JWT secret key for the GoTrue server. | +| OCR_URL | | Leave empty. | +| OCR_CALLBACK_URL | | Leave empty. | + + +### Development Services Configuration +The file `development/.env` configures secrets for the services used in local development. +An empty template for the file can be found in [`development/.env.template`](development/.env.template). + +> Make sure that your passwords have a minimal length of 8 and contain at combination of +> upper, lower and special characters. Some of the passwords will be checked for validity during startup. + +| Variable | Wert | Beschreibung | +|-------------------|----------|------------------------------------------| +| STORAGE_USER | _custom_ | Username for the MinIO container. | +| STORAGE_PASSWORD | _custom_ | Password for the MinIO container. | +| DB_USER | postgres | Username for the PostgreSQL container. | +| DB_PASSWORD | _custom_ | Password for the PostgreSQL container. | +| PGADMIN_EMAIL | _custom_ | Email for the PgAdmin container. | +| PGADMIN_PASSWORD | _custom_ | Password for the PgAdmin container. | +| GOTRUE_JWT_SECRET | _custom_ | JWT Secret Key for the GoTrue container. | diff --git a/apps/client-asset-sg-e2e/cypress.config.ts b/apps/client-asset-sg-e2e/cypress.config.ts index ec4ed885..39337d99 100644 --- a/apps/client-asset-sg-e2e/cypress.config.ts +++ b/apps/client-asset-sg-e2e/cypress.config.ts @@ -1,5 +1,5 @@ -import { defineConfig } from 'cypress'; import { nxE2EPreset } from '@nrwl/cypress/plugins/cypress-preset'; +import { defineConfig } from 'cypress'; export default defineConfig({ e2e: nxE2EPreset(__dirname), diff --git a/apps/client-asset-sg-e2e/src/support/commands.ts b/apps/client-asset-sg-e2e/src/support/commands.ts index 4200179b..384d6715 100644 --- a/apps/client-asset-sg-e2e/src/support/commands.ts +++ b/apps/client-asset-sg-e2e/src/support/commands.ts @@ -18,7 +18,7 @@ declare namespace Cypress { // // -- This is a parent command -- Cypress.Commands.add('login', (email, password) => { - console.log('Custom command example: Login', email, password); + console.log('Custom command example: Login'); }); // // -- This is a child command -- diff --git a/apps/client-asset-sg/docker/Dockerfile b/apps/client-asset-sg/docker/Dockerfile index ae87bd02..5842e09c 100644 --- a/apps/client-asset-sg/docker/Dockerfile +++ b/apps/client-asset-sg/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM node:16-alpine as ui-builder +FROM node:20-alpine as app-builder WORKDIR /app COPY . . @@ -11,10 +11,9 @@ RUN npx nx build client-asset-sg # final image build FROM nginx:mainline-alpine -LABEL maintainer=support@lambda-it.ch WORKDIR /usr/share/nginx/html -COPY --from=ui-builder /app/dist/apps/client-asset-sg . +COPY --from=app-builder /app/dist/apps/client-asset-sg . # this nginx base image will parse the template and will move it to # /etc/nginx/conf.d/default.conf before it starts nginx process diff --git a/apps/client-asset-sg/project.json b/apps/client-asset-sg/project.json index dceecf5a..b99fba3a 100644 --- a/apps/client-asset-sg/project.json +++ b/apps/client-asset-sg/project.json @@ -1,93 +1,120 @@ { - "name": "client-asset-sg", - "$schema": "../../node_modules/nx/schemas/project-schema.json", - "projectType": "application", - "sourceRoot": "apps/client-asset-sg/src", - "prefix": "asset-sg", - "targets": { - "build": { - "executor": "@angular-devkit/build-angular:browser", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/apps/client-asset-sg", - "index": "apps/client-asset-sg/src/index.html", - "main": "apps/client-asset-sg/src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "apps/client-asset-sg/tsconfig.app.json", - "inlineStyleLanguage": "scss", - "assets": ["apps/client-asset-sg/src/favicon.ico", "apps/client-asset-sg/src/assets"], - "styles": ["apps/client-asset-sg/src/styles.scss"], - "scripts": [] + "name": "client-asset-sg", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "sourceRoot": "apps/client-asset-sg/src", + "prefix": "asset-sg", + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:browser", + "outputs": [ + "{options.outputPath}" + ], + "options": { + "outputPath": "dist/apps/client-asset-sg", + "index": "apps/client-asset-sg/src/index.html", + "main": "apps/client-asset-sg/src/main.ts", + "polyfills": [ + "zone.js" + ], + "tsConfig": "apps/client-asset-sg/tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + "apps/client-asset-sg/src/favicon.ico", + "apps/client-asset-sg/src/assets" + ], + "styles": [ + "apps/client-asset-sg/src/styles.scss" + ], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "1.2mb", + "maximumError": "1.3mb" }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "1.2mb", - "maximumError": "1.3mb" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "2kb", - "maximumError": "4kb" - } - ], - "outputHashing": "all", - "fileReplacements": [ - { - "replace": "apps/client-asset-sg/src/environments/environment.ts", - "with": "apps/client-asset-sg/src/environments/environment.prod.ts" - } - ] - }, - "development": { - "buildOptimizer": false, - "optimization": false, - "vendorChunk": true, - "extractLicenses": false, - "sourceMap": true, - "namedChunks": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "browserTarget": "client-asset-sg:build:production" - }, - "development": { - "browserTarget": "client-asset-sg:build:development" - } - }, - "defaultConfiguration": "development", - "options": { - "proxyConfig": "apps/client-asset-sg/proxy.conf.json" + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" } - }, - "extract-i18n": { - "executor": "@angular-devkit/build-angular:extract-i18n", - "options": { - "browserTarget": "client-asset-sg:build" + ], + "outputHashing": "all", + "fileReplacements": [ + { + "replace": "apps/client-asset-sg/src/environments/environment.ts", + "with": "apps/client-asset-sg/src/environments/environment.prod.ts" } + ] }, - "lint": { - "executor": "@nrwl/linter:eslint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": ["apps/client-asset-sg/**/*.ts", "apps/client-asset-sg/**/*.html"] + "int": { + "fileReplacements": [ + { + "replace": "apps/client-asset-sg/src/environments/environment.ts", + "with": "apps/client-asset-sg/src/environments/environment.int.ts" } + ] }, - "test": { - "executor": "@nrwl/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "apps/client-asset-sg/jest.config.ts", - "passWithNoTests": true - } + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "browserTarget": "client-asset-sg:build:production" + }, + "int": { + "browserTarget": "client-asset-sg:build:int" + }, + "development": { + "browserTarget": "client-asset-sg:build:development" + } + }, + "defaultConfiguration": "development", + "options": { + "proxyConfig": "apps/client-asset-sg/proxy.conf.json" + } + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "client-asset-sg:build" + } + }, + "lint": { + "executor": "@nrwl/linter:eslint", + "outputs": [ + "{options.outputFile}" + ], + "options": { + "lintFilePatterns": [ + "apps/client-asset-sg/**/*.ts", + "apps/client-asset-sg/**/*.html" + ] + } }, - "tags": [] + "test": { + "executor": "@nrwl/jest:jest", + "outputs": [ + "{workspaceRoot}/coverage/{projectRoot}" + ], + "options": { + "jestConfig": "apps/client-asset-sg/jest.config.ts", + "passWithNoTests": true + } + } + }, + "tags": [] } diff --git a/apps/client-asset-sg/src/app/app.component.html b/apps/client-asset-sg/src/app/app.component.html index 51447d42..52c102ab 100644 --- a/apps/client-asset-sg/src/app/app.component.html +++ b/apps/client-asset-sg/src/app/app.component.html @@ -1,10 +1,10 @@ - + - +
- +
-
- +
+
diff --git a/apps/client-asset-sg/src/app/app.component.spec.ts b/apps/client-asset-sg/src/app/app.component.spec.ts deleted file mode 100644 index 5c44f3d5..00000000 --- a/apps/client-asset-sg/src/app/app.component.spec.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { AppComponent } from './app.component'; -import { NxWelcomeComponent } from './nx-welcome.component'; - -describe('AppComponent', () => { - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [AppComponent, NxWelcomeComponent], - }).compileComponents(); - }); - - it('should create the app', () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app).toBeTruthy(); - }); - - it(`should have as title 'client-asset-sg'`, () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('client-asset-sg'); - }); - - it('should render title', () => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.nativeElement as HTMLElement; - expect(compiled.querySelector('h1')?.textContent).toContain('Welcome client-asset-sg'); - }); -}); diff --git a/apps/client-asset-sg/src/app/app.component.ts b/apps/client-asset-sg/src/app/app.component.ts index 7ec1d29a..f6cd7e3a 100644 --- a/apps/client-asset-sg/src/app/app.component.ts +++ b/apps/client-asset-sg/src/app/app.component.ts @@ -1,43 +1,69 @@ +import { HttpClient } from '@angular/common/http'; import { Component, inject } from '@angular/core'; +import { Router } from '@angular/router'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; +import { Store } from '@ngrx/store'; import { WINDOW } from 'ngx-window-token'; -import { debounceTime, fromEvent, startWith } from 'rxjs'; +import { debounceTime, fromEvent, map, startWith } from 'rxjs'; import { assert } from 'tsafe'; -import { AppPortalService, setCssCustomProperties } from '@asset-sg/client-shared'; -import { FavouriteService } from '@asset-sg/favourite'; +import { AuthService } from '@asset-sg/auth'; +import { AppPortalService, appSharedStateActions, setCssCustomProperties } from '@asset-sg/client-shared'; + +import { AppState } from './state/app-state'; const fullHdWidth = 1920; @UntilDestroy() @Component({ - selector: 'asset-sg-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.scss'], + selector: 'asset-sg-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.scss'], }) export class AppComponent { - private _wndw = inject(WINDOW); - - public appPortalService = inject(AppPortalService); - private _favouriteService = inject(FavouriteService); - - constructor() { - const wndw = this._wndw; - assert(wndw != null); - - fromEvent(wndw, 'resize') - .pipe(debounceTime(50), startWith(null), untilDestroyed(this)) - .subscribe(() => { - let fontSize = '1rem'; - const width = window.innerWidth; - if (width >= fullHdWidth) { - fontSize = '1rem'; - } else if (width >= 0.8 * fullHdWidth) { - fontSize = `${width / fullHdWidth}rem`; - } else { - fontSize = '0.8rem'; - } - setCssCustomProperties(wndw.document.documentElement, ['font-size', fontSize]); - }); - } + private _wndw = inject(WINDOW); + private _httpClient = inject(HttpClient); + public appPortalService = inject(AppPortalService); + private store = inject(Store); + public readonly router: Router = inject(Router); + + constructor(private readonly _authService: AuthService) { + this._httpClient + .get('api/oauth-config/config') + .pipe( + map((response: any) => { + return response; + }), + ) + .subscribe(async oAuthConfig => { + await this._authService.configureOAuth( + oAuthConfig.oauth_issuer, + oAuthConfig.oauth_clientId, + oAuthConfig.oauth_scope, + oAuthConfig.oauth_showDebugInformation, + oAuthConfig.oauth_tokenEndpoint, + ); + + this.store.dispatch(appSharedStateActions.loadUserProfile()); + this.store.dispatch(appSharedStateActions.loadReferenceData()); + }); + + const wndw = this._wndw; + assert(wndw != null); + + fromEvent(wndw, 'resize') + .pipe(debounceTime(50), startWith(null), untilDestroyed(this)) + .subscribe(() => { + let fontSize; + const width = window.innerWidth; + if (width >= fullHdWidth) { + fontSize = '1rem'; + } else if (width >= 0.8 * fullHdWidth) { + fontSize = `${width / fullHdWidth}rem`; + } else { + fontSize = '0.8rem'; + } + setCssCustomProperties(wndw.document.documentElement, ['font-size', fontSize]); + }); + } } diff --git a/apps/client-asset-sg/src/app/app.module.ts b/apps/client-asset-sg/src/app/app.module.ts index 2cfdf690..abfd15f4 100644 --- a/apps/client-asset-sg/src/app/app.module.ts +++ b/apps/client-asset-sg/src/app/app.module.ts @@ -19,14 +19,14 @@ import { PushModule } from '@rx-angular/template/push'; import * as O from 'fp-ts/Option'; import * as C from 'io-ts/Codec'; -import { AuthInterceptor } from '@asset-sg/auth'; +import { AuthInterceptor, AuthModule } from '@asset-sg/auth'; import { - AnchorComponent, - ButtonComponent, - CURRENT_LANG, - TranslateTsLoader, - currentLangFactory, - icons, + AnchorComponent, + ButtonComponent, + CURRENT_LANG, + TranslateTsLoader, + currentLangFactory, + icons, } from '@asset-sg/client-shared'; import { storeLogger } from '@asset-sg/core'; @@ -36,6 +36,7 @@ import { adminGuard, editorGuard } from './app-guards'; import { assetsPageMatcher } from './app-matchers'; import { AppComponent } from './app.component'; import { AppBarComponent, MenuBarComponent, NotFoundComponent, RedirectToLangComponent } from './components'; +import { ErrorComponent } from './components/error/error.component'; import { appTranslations } from './i18n'; import { AppSharedStateEffects } from './state'; import { appSharedStateReducer } from './state/app-shared.reducer'; @@ -43,89 +44,104 @@ import { appSharedStateReducer } from './state/app-shared.reducer'; registerLocaleData(locale_deCH, 'de-CH'); @NgModule({ - declarations: [AppComponent, RedirectToLangComponent, NotFoundComponent, AppBarComponent, MenuBarComponent], - imports: [ - BrowserModule, - BrowserAnimationsModule, - HttpClientModule, - RouterModule.forRoot([ - { - path: ':lang/a', - loadChildren: () => import('@asset-sg/auth').then(m => m.AuthModule), - }, - { - path: ':lang/profile', - loadChildren: () => import('@asset-sg/profile').then(m => m.ProfileModule), - }, - { - path: ':lang/admin', - loadChildren: () => import('@asset-sg/admin').then(m => m.AdminModule), - canActivate: [adminGuard], - }, - { - path: ':lang/asset-admin', - loadChildren: () => import('@asset-sg/asset-editor').then(m => m.AssetEditorModule), - canActivate: [editorGuard], - }, - { - matcher: assetsPageMatcher, - loadChildren: () => import('@asset-sg/asset-viewer').then(m => m.AssetViewerModule), - }, - { - path: 'not-found', - component: NotFoundComponent, - }, - { - path: '**', - component: RedirectToLangComponent, - }, - ]), - TranslateModule.forRoot({ - loader: { provide: TranslateLoader, useFactory: () => new TranslateTsLoader(appTranslations) }, - }), - StoreRouterConnectingModule.forRoot({ serializer: FullRouterStateSerializer, stateKey: 'router' }), - StoreModule.forRoot( - { router: routerReducer, shared: appSharedStateReducer }, - { - metaReducers: environment.ngrxStoreLoggerEnabled ? [storeLogger()] : [], - runtimeChecks: { - strictStateImmutability: false, - }, - }, - ), - EffectsModule.forRoot([AppSharedStateEffects]), - ForModule, - LetModule, - PushModule, + declarations: [ + AppComponent, + RedirectToLangComponent, + NotFoundComponent, + AppBarComponent, + MenuBarComponent, + ErrorComponent, + ], + imports: [ + BrowserModule, + BrowserAnimationsModule, + HttpClientModule, + RouterModule.forRoot([ + { + path: ':lang/a', + loadChildren: () => import('@asset-sg/auth').then(m => m.AuthModule), + }, + { + path: ':lang/profile', + loadChildren: () => import('@asset-sg/profile').then(m => m.ProfileModule), + }, + { + path: ':lang/admin', + loadChildren: () => import('@asset-sg/admin').then(m => m.AdminModule), + canActivate: [adminGuard], + }, + { + path: ':lang/asset-admin', + loadChildren: () => import('@asset-sg/asset-editor').then(m => m.AssetEditorModule), + canActivate: [editorGuard], + }, + { + path: ':lang/error', + component: ErrorComponent, + }, + { + matcher: assetsPageMatcher, + loadChildren: () => import('@asset-sg/asset-viewer').then(m => m.AssetViewerModule), + }, + { + path: 'not-found', + component: NotFoundComponent, + }, + { + path: '**', + component: RedirectToLangComponent, + }, + ]), + TranslateModule.forRoot({ + loader: { provide: TranslateLoader, useFactory: () => new TranslateTsLoader(appTranslations) }, + }), + StoreRouterConnectingModule.forRoot({ serializer: FullRouterStateSerializer, stateKey: 'router' }), + StoreModule.forRoot( + { router: routerReducer, shared: appSharedStateReducer }, + { + metaReducers: environment.ngrxStoreLoggerEnabled ? [storeLogger()] : [], + runtimeChecks: { + strictStateImmutability: false, + }, + }, + ), + EffectsModule.forRoot([AppSharedStateEffects]), + ForModule, + LetModule, + PushModule, - SvgIconComponent, + SvgIconComponent, - AnchorComponent, - ButtonComponent, - DialogModule, - A11yModule, - ], - providers: [ - provideSvgIcons(icons), - { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }, - { provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: { appearance: 'fill', floatLabel: 'auto' } }, - { provide: CURRENT_LANG, useFactory: currentLangFactory }, - ], - bootstrap: [AppComponent], + AnchorComponent, + ButtonComponent, + DialogModule, + A11yModule, + AuthModule, + ], + providers: [ + provideSvgIcons(icons), + { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }, + { provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: { appearance: 'fill', floatLabel: 'auto' } }, + { provide: CURRENT_LANG, useFactory: currentLangFactory }, + ], + bootstrap: [AppComponent], }) export class AppModule { - private _translateService = inject(TranslateService); - constructor() { - this._translateService.setDefaultLang('de'); - } + private _translateService = inject(TranslateService); + + constructor() { + this._translateService.setDefaultLang('de'); + } } export interface Encoder { - readonly encode: (a: A) => O; + readonly encode: (a: A) => O; } + function optionFromNullable(encoder: Encoder): Encoder> { - return { - encode: O.fold(() => null, encoder.encode), - }; + return { + encode: O.fold(() => null, encoder.encode), + }; } + const foooobar = optionFromNullable(C.string); diff --git a/apps/client-asset-sg/src/app/components/app-bar/app-bar.component.html b/apps/client-asset-sg/src/app/components/app-bar/app-bar.component.html index eda685f8..8eb2d1a1 100644 --- a/apps/client-asset-sg/src/app/components/app-bar/app-bar.component.html +++ b/apps/client-asset-sg/src/app/components/app-bar/app-bar.component.html @@ -1,5 +1,5 @@ - +