diff --git a/.github/workflows/check-types.yml b/.github/workflows/check-types.yml index db87cceaa1..c9ec77c9b0 100644 --- a/.github/workflows/check-types.yml +++ b/.github/workflows/check-types.yml @@ -83,20 +83,6 @@ jobs: run: | pnpm run check - - name: Check v2 export function typescript types - if: always() - shell: bash - working-directory: apps/func-migration-v2-export - run: | - pnpm run check - - - name: Check v3 import function typescript types - if: always() - shell: bash - working-directory: apps/func-migration-v3-import - run: | - pnpm run check - - name: Check backend-docker typescript types if: always() shell: bash diff --git a/.github/workflows/v3_klickeruzhprod-migration-export.yml b/.github/workflows/v3_klickeruzhprod-migration-export.yml deleted file mode 100644 index f0779d7f9b..0000000000 --- a/.github/workflows/v3_klickeruzhprod-migration-export.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Build and deploy func-migration-v2-export to Azure Function App (Production) - -on: - push: - branches: - - 'v3' - paths: - - 'apps/func-migration-v2-export/**' - - '.github/workflows/v3_klickeruzhprod-migration-export**' - workflow_dispatch: - -env: - AZURE_FUNCTIONAPP_PACKAGE_PATH: 'apps/func-migration-v2-export' - NODE_VERSION: '20.17.0' # set this to the node version to use (supports 8.x, 10.x, 12.x) - -jobs: - build-and-deploy: - runs-on: ubuntu-latest - steps: - - name: 'Checkout GitHub Action' - uses: actions/checkout@v2 - - - name: Setup Node ${{ env.NODE_VERSION }} Environment - uses: actions/setup-node@v1 - with: - node-version: ${{ env.NODE_VERSION }} - - - uses: pnpm/action-setup@v2 - with: - version: 9.10.0 - - - name: 'Resolve Project Dependencies Using Npm' - shell: bash - run: | - pnpm dlx turbo@2.1.0 prune --scope @klicker-uzh/func-migration-v2-export - pushd out - echo "node-linker=hoisted" > .npmrc - pnpm install --frozen-lockfile --ignore-scripts --strict-peer-dependencies - pnpm run build - mv apps/func-migration-v2-export apps/func - mv apps/func/host.json . - popd - - - name: 'Run Azure Functions Action' - uses: Azure/functions-action@v1 - id: fa - with: - app-name: 'klickeruzhprod-migration-export' - package: out - publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_1286111D936B447EA24EDB53EE84C138 }} diff --git a/.github/workflows/v3_klickeruzhprod-migration-import.yml b/.github/workflows/v3_klickeruzhprod-migration-import.yml deleted file mode 100644 index abf72b270a..0000000000 --- a/.github/workflows/v3_klickeruzhprod-migration-import.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: Build and deploy func-migration-v3-import to Azure Function App (Production) - -on: - push: - branches: - - 'v3' - paths: - - 'apps/func-migration-v3-import/**' - - '.github/workflows/v3_klickeruzhprod-migration-import**' - workflow_dispatch: - -env: - AZURE_FUNCTIONAPP_PACKAGE_PATH: 'apps/func-migration-v3-import' - NODE_VERSION: '20.17.0' # set this to the node version to use (supports 8.x, 10.x, 12.x) - -jobs: - build-and-deploy: - runs-on: windows-latest - steps: - - name: 'Checkout GitHub Action' - uses: actions/checkout@v2 - - - name: Setup Node ${{ env.NODE_VERSION }} Environment - uses: actions/setup-node@v1 - with: - node-version: ${{ env.NODE_VERSION }} - - - uses: pnpm/action-setup@v2 - with: - version: 9.10.0 - - - name: 'Resolve Project Dependencies Using Npm' - shell: bash - run: | - pnpm dlx turbo@2.1.0 prune --scope @klicker-uzh/func-migration-v3-import - pushd out - echo "node-linker=hoisted" > .npmrc - pnpm install --frozen-lockfile --ignore-scripts --strict-peer-dependencies - pnpm run build - mv apps/func-migration-v3-import apps/func - mv apps/func/host.json . - cp packages/prisma/dist/schema.prisma apps/func/dist/schema.prisma - cp packages/prisma/dist/*.so.node apps/func/dist/ - popd - - - name: 'Run Azure Functions Action' - uses: Azure/functions-action@v1 - id: fa - with: - app-name: 'klickeruzhprod-migration-import' - package: out - publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_DD28D6A97D214920903D9DA7C06D7C96 }} diff --git a/.versionrc.js b/.versionrc.js index 8a60220da8..817cd3746b 100644 --- a/.versionrc.js +++ b/.versionrc.js @@ -12,8 +12,6 @@ module.exports = { 'apps/backend-docker/', 'apps/func-incoming-responses/', 'apps/func-response-processor/', - 'apps/func-migration-v2-export/', - 'apps/func-migration-v3-import/', 'apps/frontend-manage/', 'apps/frontend-pwa/', 'apps/frontend-control/', diff --git a/.vscode/settings.json b/.vscode/settings.json index 5abc4746de..ce8fc67e5d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,12 +1,10 @@ { - "azureFunctions.deploySubpath": "apps/func-migration-v2-export", "azureFunctions.postDeployTask": "npm install (serverless)", "azureFunctions.projectLanguage": "TypeScript", "azureFunctions.projectLanguageModel": 4, "azureFunctions.projectRuntime": "~4", "debug.internalConsoleOptions": "neverOpen", "azureFunctions.preDeployTask": "npm prune (serverless)", - "azureFunctions.projectSubpath": "apps/func-migration-v2-export", "githubPullRequests.ignoredPullRequestBranches": ["v3"], "editor.formatOnSave": true, "sonarlint.connectedMode.project": { diff --git a/CHANGELOG.md b/CHANGELOG.md index 07cbe6656f..9d10eda7f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,28 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [3.3.0-alpha.7](https://github.com/uzh-bf/klicker-uzh/compare/v3.3.0-alpha.6...v3.3.0-alpha.7) (2024-11-05) + + +### Enhancements + +* **apps/frontend-manage:** display QR code on evaluation page for live quizzes ([#4356](https://github.com/uzh-bf/klicker-uzh/issues/4356)) ([7a734d1](https://github.com/uzh-bf/klicker-uzh/commit/7a734d11aae77ae306c951388b8a22360a1162b9)) + +## [3.3.0-alpha.6](https://github.com/uzh-bf/klicker-uzh/compare/v3.3.0-alpha.5...v3.3.0-alpha.6) (2024-11-03) + + +### Bug Fixes + +* **packages/graphql:** ensure that repetition interval remains below maximum value ([#4348](https://github.com/uzh-bf/klicker-uzh/issues/4348)) ([30f4953](https://github.com/uzh-bf/klicker-uzh/commit/30f495306567711e237b7a3ddc950473aa82343e)) + +## [3.3.0-alpha.5](https://github.com/uzh-bf/klicker-uzh/compare/v3.3.0-alpha.4...v3.3.0-alpha.5) (2024-10-31) + + +### Bug Fixes + +* ensure that re-ordered answer options on choices questions are displayed consistently ([#4339](https://github.com/uzh-bf/klicker-uzh/issues/4339)) ([e139988](https://github.com/uzh-bf/klicker-uzh/commit/e1399888081f3389f7d0437be1c2e7b2041b3243)) +* make sure that participants on group leaderboard are always in correct order ([7fb55ed](https://github.com/uzh-bf/klicker-uzh/commit/7fb55ed2031d26e6c8855f468b60fa9315f6960f)) + ## [3.3.0-alpha.4](https://github.com/uzh-bf/klicker-uzh/compare/v3.3.0-alpha.3...v3.3.0-alpha.4) (2024-10-24) diff --git a/README.md b/README.md index 3ddf28c1df..36e6476cd6 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ > Please note that this is the repository branch for KlickerUZH v3.0 released in August 2023. If you would like to have more information on the new concept of v3.0, have a look at our [public discussion](https://community.klicker.uzh.ch/t/klickeruzh-v3-0-concept-and-request-for-feedback/79). > -> Please navigate to the [dev branch](https://github.com/uzh-bf/klicker-uzh/tree/dev) for the older [KlickerUZH v2.0](https://app.klicker.uzh.ch/), which will be available until the end of 2023. To migrate to KlickerUZH v3.0, start the [migration process](https://manage.klicker.uzh.ch/migration). +> Please navigate to the [dev branch](https://github.com/uzh-bf/klicker-uzh/tree/dev) for the older [KlickerUZH v2.0](https://app.klicker.uzh.ch/), which is not publically available anymore. `klicker-uzh` is the code repository of the [KlickerUZH](https://www.klicker.uzh.ch/) open-source audience interaction platform. KlickerUZH is developed by the Teaching Center of the Department of Finance at the University of Zurich, Switzerland. @@ -17,7 +17,6 @@ KlickerUZH v3.0 uses multiple different web applications and services, which com - [Backend Docker](https://github.com/uzh-bf/klicker-uzh/tree/v3/apps/backend-docker) is the main backend service of KlickerUZH. - [Backend Responses](https://github.com/uzh-bf/klicker-uzh/tree/v3/apps/func-incoming-responses) is a service that handles incoming student responses during a live quizzes and puts them into an Azure queue for improved load handling. - [Backend Response Processor](https://github.com/uzh-bf/klicker-uzh/tree/v3/apps/func-response-processor) accesses queued elements from the aforementioned service and processes them by computing scores and experience points, updating the cache, etc. -- The [v2.0 Export](https://github.com/uzh-bf/klicker-uzh/tree/v3/apps/func-migration-v2-export) and [v3.0 Import](https://github.com/uzh-bf/klicker-uzh/tree/v3/apps/func-migration-v3-import) folders contain serverless Azure Functions related to the migration from KlickerUZH v2.0 to v3.0. In addition to the key application components, this repository also includes the codebases for our landing page and documentation at [www.klicker.uzh.ch](https://www.klicker.uzh.ch/), as well as deployment scripts for Helm/Kubernetes. An updated deployment documentation for self-hosting KlickerUZH v3.0 will be added until the end of the year. diff --git a/_run_migration_services.sh b/_run_migration_services.sh deleted file mode 100755 index 3a4bfd4d0d..0000000000 --- a/_run_migration_services.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -docker compose up listmonk listmonk_db mailhog diff --git a/apps/auth/package.json b/apps/auth/package.json index f91a0b4ed6..f6654d92c7 100644 --- a/apps/auth/package.json +++ b/apps/auth/package.json @@ -1,6 +1,6 @@ { "name": "@klicker-uzh/auth", - "version": "3.3.0-alpha.4", + "version": "3.3.0-alpha.7", "license": "AGPL-3.0", "dependencies": { "@klicker-uzh/i18n": "workspace:*", diff --git a/apps/backend-docker/package.json b/apps/backend-docker/package.json index b8c7a4f0ab..f16185f943 100644 --- a/apps/backend-docker/package.json +++ b/apps/backend-docker/package.json @@ -1,6 +1,6 @@ { "name": "@klicker-uzh/backend-docker", - "version": "3.3.0-alpha.4", + "version": "3.3.0-alpha.7", "license": "AGPL-3.0", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/apps/backend-docker/scripts/fixQuestionData.ts b/apps/backend-docker/scripts/fixQuestionData.ts deleted file mode 100644 index 3ea09a31ca..0000000000 --- a/apps/backend-docker/scripts/fixQuestionData.ts +++ /dev/null @@ -1,41 +0,0 @@ -// pn exec:prod scripts/fixQuestionData.ts - -import { PrismaClient } from '@klicker-uzh/prisma' - -const prisma = new PrismaClient() - -const questionInstances = await prisma.questionInstance.findMany() - -console.log(questionInstances.length) - -questionInstances.forEach((questionInstance) => { - const expectedKeys = [ - 'id', - 'name', - 'type', - 'content', - 'options', - 'ownerId', - 'createdAt', - 'isDeleted', - 'updatedAt', - 'isArchived', - 'originalId', - 'displayMode', // TODO: will be moved to options - 'explanation', - 'pointsMultiplier', // TODO: will be moved to options - 'hasSampleSolution', // TODO: will be moved to options - 'hasAnswerFeedbacks', // TODO: will be moved to options - 'attachments', // TODO: could be purged from existing questionData - 'contentPlain', // TODO: could be purged from existing questionData - ] - - const existingKeys = Object.keys(questionInstance.questionData) - - const difference = existingKeys.filter((key) => !expectedKeys.includes(key)) - if (difference.length !== 0) { - console.log(difference) - } -}) - -process.exit(0) diff --git a/apps/docs/docs/getting_started/migration.mdx b/apps/docs/docs/getting_started/migration.mdx deleted file mode 100644 index eade3e5bef..0000000000 --- a/apps/docs/docs/getting_started/migration.mdx +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: Migration from v2.0 ---- - -:::warning -The migration process is no longer officially supported and will be removed soon. -::: - -This article contains a short description on how to start the migration process from v2.0 to v3.0. - -1. Before starting the migration, you need to create an account in the new KlickerUZH v3.0. For this, head to [http://manage.klicker.uzh.ch/login](http://manage.klicker.uzh.ch/login) and use your Edu-ID credentials to log in. If you do not have an Edu-ID account, you can create one [here](https://eduid.ch/web/registration/1/). Creating an Edu-ID account is free of charge and **not** limited to Swiss universities. -2. Once you logged in, you will be asked to make some initial configuration settings. Read the instructions and confirm your settings. You can also change them later in the settings menu. -3. You will now see the question pool overview. From here, you can start the migration process by clicking on the `Migration`-button in the menu bar or use the direct link [https://manage.klicker.uzh.ch/migration](https://manage.klicker.uzh.ch/migration). -4. Follow the instructions on the migration page. You will be asked to enter your old KlickerUZH v2.0 email address. After that, you will have to confirm the migration by clicking on the link in the email you will receive. Should you encounter problems or not have access to your old email address anymore, please contact us through our [community](https://community.klicker.uzh.ch/) or other communication channels. diff --git a/apps/docs/package.json b/apps/docs/package.json index 07c724928f..c14b8b7a6f 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@klicker-uzh/docs", - "version": "3.3.0-alpha.4", + "version": "3.3.0-alpha.7", "license": "AGPL-3.0", "devDependencies": { "@docusaurus/core": "~3.5.2", diff --git a/apps/docs/sidebars.js b/apps/docs/sidebars.js index 66957dc3f0..baa3739c4b 100644 --- a/apps/docs/sidebars.js +++ b/apps/docs/sidebars.js @@ -3,7 +3,6 @@ module.exports = { 'Getting Started': [ 'getting_started/welcome', 'getting_started/core_concepts', - 'getting_started/migration', ], 'Lecturer Application': [ 'tutorials/supported_element_types', diff --git a/apps/frontend-control/package.json b/apps/frontend-control/package.json index af547ac630..464f2dfd6b 100644 --- a/apps/frontend-control/package.json +++ b/apps/frontend-control/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@klicker-uzh/frontend-control", - "version": "3.3.0-alpha.4", + "version": "3.3.0-alpha.7", "license": "AGPL-3.0", "dependencies": { "@apollo/client": "3.11.8", diff --git a/apps/frontend-manage/package.json b/apps/frontend-manage/package.json index 52b7915684..86e9f06223 100644 --- a/apps/frontend-manage/package.json +++ b/apps/frontend-manage/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@klicker-uzh/frontend-manage", - "version": "3.3.0-alpha.4", + "version": "3.3.0-alpha.7", "license": "AGPL-3.0", "dependencies": { "@apollo/client": "3.11.8", @@ -19,6 +19,8 @@ "@klicker-uzh/prisma": "workspace:*", "@klicker-uzh/shared-components": "workspace:*", "@socialgouv/matomo-next": "1.9.1", + "@tanstack/react-table": "8.20.5", + "@uidotdev/usehooks": "2.4.1", "@uzh-bf/design-system": "3.0.0-alpha.32", "dayjs": "1.11.13", "deepmerge": "4.3.1", @@ -30,6 +32,7 @@ "is-hotkey": "0.2.0", "js-search": "2.0.1", "lodash": "4.17.21", + "nanoid": "5.0.8", "next": "15.0.0", "next-intl": "3.21.1", "react": "18.3.1", diff --git a/apps/frontend-manage/src/components/common/Header.tsx b/apps/frontend-manage/src/components/common/Header.tsx index 95d123b485..879622004d 100644 --- a/apps/frontend-manage/src/components/common/Header.tsx +++ b/apps/frontend-manage/src/components/common/Header.tsx @@ -75,18 +75,6 @@ function Header({ user }: HeaderProps): React.ReactElement { ))} - router.push('/migration')} - label={t('manage.general.migration')} - className={{ - label: twMerge( - 'bg-gradient-to-r from-white to-white bg-[length:0%_2px] bg-left-bottom bg-no-repeat text-base font-bold transition-all duration-500 ease-out group-hover:bg-[length:100%_2px]', - router.pathname === '/migration' && - 'text-red underline decoration-2 underline-offset-[0.3rem]' - ), - root: 'group text-white transition-all duration-300 ease-in-out hover:bg-inherit', - }} - />
)} diff --git a/apps/frontend-manage/src/components/evaluation/ElementEvaluation.tsx b/apps/frontend-manage/src/components/evaluation/ElementEvaluation.tsx index f4b2c5b163..a2aca63a92 100644 --- a/apps/frontend-manage/src/components/evaluation/ElementEvaluation.tsx +++ b/apps/frontend-manage/src/components/evaluation/ElementEvaluation.tsx @@ -1,6 +1,7 @@ import { ElementInstanceEvaluation } from '@klicker-uzh/graphql/dist/ops' import { ChartType } from '@klicker-uzh/shared-components/src/constants' import { twMerge } from 'tailwind-merge' +import { ActivityEvaluationType } from './ActivityEvaluation' import CTEvaluation from './elements/CTEvaluation' import ChoicesEvaluation from './elements/ChoicesEvaluation' import FCEvaluation from './elements/FCEvaluation' @@ -15,6 +16,7 @@ interface ElementEvaluationProps { textSize: TextSizeType chartType: ChartType showSolution: boolean + type: ActivityEvaluationType className?: string } @@ -24,6 +26,7 @@ function ElementEvaluation({ textSize, chartType, showSolution, + type, className, }: ElementEvaluationProps) { return ( @@ -42,6 +45,7 @@ function ElementEvaluation({ textSize={textSize} chartType={chartType} showSolution={showSolution} + type={type} /> )} {currentInstance.__typename === @@ -51,6 +55,7 @@ function ElementEvaluation({ textSize={textSize} chartType={chartType} showSolution={showSolution} + type={type} /> )} {currentInstance.__typename === 'FreeElementInstanceEvaluation' && ( @@ -59,6 +64,7 @@ function ElementEvaluation({ textSize={textSize} chartType={chartType} showSolution={showSolution} + type={type} /> )} {currentInstance.__typename === diff --git a/apps/frontend-manage/src/components/evaluation/elements/ChoicesEvaluation.tsx b/apps/frontend-manage/src/components/evaluation/elements/ChoicesEvaluation.tsx index 62605e4c7e..5464b2a1ae 100644 --- a/apps/frontend-manage/src/components/evaluation/elements/ChoicesEvaluation.tsx +++ b/apps/frontend-manage/src/components/evaluation/elements/ChoicesEvaluation.tsx @@ -1,6 +1,6 @@ import { ChoicesElementInstanceEvaluation } from '@klicker-uzh/graphql/dist/ops' import { ChartType } from '@klicker-uzh/shared-components/src/constants' -import { twMerge } from 'tailwind-merge' +import { ActivityEvaluationType } from '../ActivityEvaluation' import ElementChart from '../ElementChart' import { TextSizeType } from '../textSizes' import ChoicesSidebar from './ChoicesSidebar' @@ -10,6 +10,7 @@ interface ChoicesEvaluationProps { textSize: TextSizeType chartType: ChartType showSolution: boolean + type: ActivityEvaluationType } function ChoicesEvaluation({ @@ -17,6 +18,7 @@ function ChoicesEvaluation({ textSize, chartType, showSolution, + type, }: ChoicesEvaluationProps) { return ( <> @@ -28,18 +30,13 @@ function ChoicesEvaluation({ textSize={textSize} />
-
- -
+ + ) } diff --git a/apps/frontend-manage/src/components/evaluation/elements/ChoicesSidebar.tsx b/apps/frontend-manage/src/components/evaluation/elements/ChoicesSidebar.tsx index 66a8467b49..f2283b7015 100644 --- a/apps/frontend-manage/src/components/evaluation/elements/ChoicesSidebar.tsx +++ b/apps/frontend-manage/src/components/evaluation/elements/ChoicesSidebar.tsx @@ -1,72 +1,92 @@ import { ChoicesElementInstanceEvaluation } from '@klicker-uzh/graphql/dist/ops' import { Ellipsis } from '@klicker-uzh/markdown' import { CHART_COLORS } from '@klicker-uzh/shared-components/src/constants' +import { useLocalStorage } from '@uidotdev/usehooks' import { twMerge } from 'tailwind-merge' +import { ActivityEvaluationType } from '../ActivityEvaluation' import { TextSizeType } from '../textSizes' +import LiveQuizEvaluationQRCode from './LiveQuizEvaluationQRCode' interface ChoicesSidebarProps { instance: ChoicesElementInstanceEvaluation textSize: TextSizeType showSolution: boolean + type: ActivityEvaluationType } function ChoicesSidebar({ instance, textSize, showSolution, + type, }: ChoicesSidebarProps) { + const [hideQR, setHideQR] = useLocalStorage( + `hide-qr-evaluation`, + false + ) + return ( -
-
- {instance.results.choices.map((choice, innerIndex) => { - const correctFraction = choice.count / instance.results.totalAnswers +
+
+
+ {instance.results.choices.map((choice, innerIndex) => { + const correctFraction = choice.count / instance.results.totalAnswers - return ( -
-
-
- {String.fromCharCode(65 + innerIndex)} -
-
- {Math.round(100 * correctFraction)} % + return ( +
+
+
+ {String.fromCharCode(65 + innerIndex)} +
+
+ {Math.round(100 * correctFraction)} % +
-
-
- - {choice.value} - +
+ + {choice.value} + +
-
- ) - })} + ) + })} +
+ {type === 'LiveQuiz' && !hideQR && ( + + )}
) } diff --git a/apps/frontend-manage/src/components/evaluation/elements/FTEvaluation.tsx b/apps/frontend-manage/src/components/evaluation/elements/FTEvaluation.tsx index 258e2e962e..3424cc6810 100644 --- a/apps/frontend-manage/src/components/evaluation/elements/FTEvaluation.tsx +++ b/apps/frontend-manage/src/components/evaluation/elements/FTEvaluation.tsx @@ -1,6 +1,6 @@ import { FreeElementInstanceEvaluation } from '@klicker-uzh/graphql/dist/ops' import { ChartType } from '@klicker-uzh/shared-components/src/constants' -import { twMerge } from 'tailwind-merge' +import { ActivityEvaluationType } from '../ActivityEvaluation' import ElementChart from '../ElementChart' import { TextSizeType } from '../textSizes' import FTSidebar from './FTSidebar' @@ -10,6 +10,7 @@ interface FTEvaluationProps { textSize: TextSizeType chartType: ChartType showSolution: boolean + type: ActivityEvaluationType } function FTEvaluation({ @@ -17,6 +18,7 @@ function FTEvaluation({ textSize, chartType, showSolution, + type, }: FTEvaluationProps) { return ( <> @@ -29,18 +31,12 @@ function FTEvaluation({ />
{instanceEvaluation.results.solutions && showSolution && ( -
- -
+ )} ) diff --git a/apps/frontend-manage/src/components/evaluation/elements/FTSidebar.tsx b/apps/frontend-manage/src/components/evaluation/elements/FTSidebar.tsx index 06c96b8128..ff6a2d3025 100644 --- a/apps/frontend-manage/src/components/evaluation/elements/FTSidebar.tsx +++ b/apps/frontend-manage/src/components/evaluation/elements/FTSidebar.tsx @@ -1,26 +1,45 @@ import { FreeElementInstanceEvaluation } from '@klicker-uzh/graphql/dist/ops' +import { useLocalStorage } from '@uidotdev/usehooks' import { useTranslations } from 'next-intl' +import { twMerge } from 'tailwind-merge' +import { ActivityEvaluationType } from '../ActivityEvaluation' import { TextSizeType } from '../textSizes' +import LiveQuizEvaluationQRCode from './LiveQuizEvaluationQRCode' interface FTSidebarProps { instance: FreeElementInstanceEvaluation textSize: TextSizeType showSolution: boolean + type: ActivityEvaluationType } -function FTSidebar({ instance, textSize, showSolution }: FTSidebarProps) { +function FTSidebar({ instance, textSize, showSolution, type }: FTSidebarProps) { const t = useTranslations() + const [hideQR, setHideQR] = useLocalStorage( + `hide-qr-evaluation`, + false + ) return ( -
-
- {t('manage.evaluation.keywordsSolution')}: +
+
+
+ {t('manage.evaluation.keywordsSolution')}: +
+
    + {instance.results.solutions?.map((keyword) => ( +
  • {`- ${keyword}`}
  • + ))} +
-
    - {instance.results.solutions?.map((keyword, innerIndex) => ( -
  • {`- ${keyword}`}
  • - ))} -
+ {type === 'LiveQuiz' && !hideQR && ( + + )}
) } diff --git a/apps/frontend-manage/src/components/evaluation/elements/LiveQuizEvaluationQRCode.tsx b/apps/frontend-manage/src/components/evaluation/elements/LiveQuizEvaluationQRCode.tsx new file mode 100644 index 0000000000..4574d96382 --- /dev/null +++ b/apps/frontend-manage/src/components/evaluation/elements/LiveQuizEvaluationQRCode.tsx @@ -0,0 +1,41 @@ +import { faX } from '@fortawesome/free-solid-svg-icons' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import QR from '@pages/qr/[...args]' +import { Button } from '@uzh-bf/design-system' +import { useRouter } from 'next/router' +import { Dispatch, SetStateAction } from 'react' + +function LiveQuizEvaluationQRCode({ + setHideQR, +}: { + setHideQR: Dispatch> +}) { + const router = useRouter() + const sessionRelativeLink = `/session/${router.query.id}` + + return ( +
+ + +
+ ) +} + +export default LiveQuizEvaluationQRCode diff --git a/apps/frontend-manage/src/components/evaluation/elements/NREvaluation.tsx b/apps/frontend-manage/src/components/evaluation/elements/NREvaluation.tsx index 4605936a01..93d38bc96b 100644 --- a/apps/frontend-manage/src/components/evaluation/elements/NREvaluation.tsx +++ b/apps/frontend-manage/src/components/evaluation/elements/NREvaluation.tsx @@ -1,16 +1,17 @@ import { NumericalElementInstanceEvaluation } from '@klicker-uzh/graphql/dist/ops' import { ChartType } from '@klicker-uzh/shared-components/src/constants' import { useState } from 'react' -import { twMerge } from 'tailwind-merge' +import { ActivityEvaluationType } from '../ActivityEvaluation' import ElementChart from '../ElementChart' import { TextSizeType } from '../textSizes' -import NumericalSidebar from './NumericalSidebar' +import NRSidebar from './NRSidebar' interface NREvaluationProps { instanceEvaluation: NumericalElementInstanceEvaluation textSize: TextSizeType chartType: ChartType showSolution: boolean + type: ActivityEvaluationType } export interface ShowStatisticsType { @@ -26,6 +27,7 @@ function NREvaluation({ textSize, chartType, showSolution, + type, }: NREvaluationProps) { const [showStatistics, setShowStatistics] = useState({ mean: false, @@ -46,21 +48,15 @@ function NREvaluation({ textSize={textSize} />
-
- -
+ ) } diff --git a/apps/frontend-manage/src/components/evaluation/elements/NRSidebar.tsx b/apps/frontend-manage/src/components/evaluation/elements/NRSidebar.tsx new file mode 100644 index 0000000000..40eea70472 --- /dev/null +++ b/apps/frontend-manage/src/components/evaluation/elements/NRSidebar.tsx @@ -0,0 +1,126 @@ +import { NumericalElementInstanceEvaluation } from '@klicker-uzh/graphql/dist/ops' +import { + ChartType, + STATISTICS_ORDER, +} from '@klicker-uzh/shared-components/src/constants' +import { useLocalStorage } from '@uidotdev/usehooks' +import { UserNotification } from '@uzh-bf/design-system' +import { useTranslations } from 'next-intl' +import { Dispatch, SetStateAction } from 'react' +import { twMerge } from 'tailwind-merge' +import { ActivityEvaluationType } from '../ActivityEvaluation' +import { TextSizeType } from '../textSizes' +import LiveQuizEvaluationQRCode from './LiveQuizEvaluationQRCode' +import { ShowStatisticsType } from './NREvaluation' +import Statistic from './Statistic' + +interface NRSidebarProps { + instance: NumericalElementInstanceEvaluation + chartType: ChartType + textSize: TextSizeType + showSolution: boolean + showStatistics: ShowStatisticsType + setShowStatistics: Dispatch> + type: ActivityEvaluationType +} + +function NRSidebar({ + instance, + chartType, + textSize, + showSolution, + showStatistics, + setShowStatistics, + type, +}: NRSidebarProps) { + const t = useTranslations() + const [hideQR, setHideQR] = useLocalStorage( + `hide-qr-evaluation`, + false + ) + + return ( +
+
+
+ {t('manage.evaluation.validSolutionRange')}: +
+
+ [{instance.results.minValue ?? '-∞'}, + {instance.results.maxValue ?? '+∞'}] +
+
+ {t('manage.evaluation.statistics')}: +
+ {instance.statistics ? ( + Object.entries(instance.statistics) + .slice(1) + .sort( + (a, b) => + STATISTICS_ORDER.indexOf(a[0]) - STATISTICS_ORDER.indexOf(b[0]) + ) + .map((statistic) => { + const statisticName = statistic[0] + const statisticValue = statistic[1] as number + return ( + { + setShowStatistics({ + ...showStatistics, + [statisticName]: + !showStatistics[ + statisticName as keyof ShowStatisticsType + ], + }) + }} + size={textSize.size} + /> + ) + }) + ) : ( + + {t('manage.evaluation.noStatistics')} + + )} + {showSolution && instance.results.solutionRanges && ( +
+
+ {t('manage.evaluation.correctSolutionRanges')}: +
+ {instance.results.solutionRanges.map((range, innerIndex) => ( +
+ [{range?.min ?? '-∞'},{range?.max ?? '+∞'}] +
+ ))} +
+ )} +
+ {type === 'LiveQuiz' && !hideQR && ( + + )} +
+ ) +} + +export default NRSidebar diff --git a/apps/frontend-manage/src/components/evaluation/elements/NumericalSidebar.tsx b/apps/frontend-manage/src/components/evaluation/elements/NumericalSidebar.tsx deleted file mode 100644 index 00ab73216d..0000000000 --- a/apps/frontend-manage/src/components/evaluation/elements/NumericalSidebar.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import { NumericalElementInstanceEvaluation } from '@klicker-uzh/graphql/dist/ops' -import { - ChartType, - STATISTICS_ORDER, -} from '@klicker-uzh/shared-components/src/constants' -import { UserNotification } from '@uzh-bf/design-system' -import { useTranslations } from 'next-intl' -import { Dispatch, SetStateAction } from 'react' -import { TextSizeType } from '../textSizes' -import { ShowStatisticsType } from './NREvaluation' -import Statistic from './Statistic' - -interface NumericalSidebarProps { - instance: NumericalElementInstanceEvaluation - chartType: ChartType - textSize: TextSizeType - showSolution: boolean - showStatistics: ShowStatisticsType - setShowStatistics: Dispatch> -} - -function NumericalSidebar({ - instance, - chartType, - textSize, - showSolution, - showStatistics, - setShowStatistics, -}: NumericalSidebarProps) { - const t = useTranslations() - - return ( -
-
- {t('manage.evaluation.validSolutionRange')}: -
-
- [{instance.results.minValue ?? '-∞'},{instance.results.maxValue ?? '+∞'} - ] -
-
{t('manage.evaluation.statistics')}:
- {instance.statistics ? ( - Object.entries(instance.statistics) - .slice(1) - .sort( - (a, b) => - STATISTICS_ORDER.indexOf(a[0]) - STATISTICS_ORDER.indexOf(b[0]) - ) - .map((statistic) => { - const statisticName = statistic[0] - const statisticValue = statistic[1] as number - return ( - { - setShowStatistics({ - ...showStatistics, - [statisticName]: - !showStatistics[ - statisticName as keyof ShowStatisticsType - ], - }) - }} - size={textSize.size} - /> - ) - }) - ) : ( - - {t('manage.evaluation.noStatistics')} - - )} - {showSolution && instance.results.solutionRanges && ( -
-
- {t('manage.evaluation.correctSolutionRanges')}: -
- {instance.results.solutionRanges.map((range, innerIndex) => ( -
- [{range?.min ?? '-∞'},{range?.max ?? '+∞'}] -
- ))} -
- )} -
- ) -} - -export default NumericalSidebar diff --git a/apps/frontend-manage/src/components/evaluation/hooks/useChartTypeUpdate.tsx b/apps/frontend-manage/src/components/evaluation/hooks/useChartTypeUpdate.tsx index dd54dca9b6..ea736d5f2a 100644 --- a/apps/frontend-manage/src/components/evaluation/hooks/useChartTypeUpdate.tsx +++ b/apps/frontend-manage/src/components/evaluation/hooks/useChartTypeUpdate.tsx @@ -7,8 +7,8 @@ import { useEffect } from 'react' interface UseChartTypeUpdateProps { activeInstance: number - activeElementType: ElementType - chartType: ChartType + activeElementType?: ElementType + chartType?: ChartType setChartType: (newType: ChartType) => void } @@ -19,7 +19,11 @@ function useChartTypeUpdate({ setChartType, }: UseChartTypeUpdateProps) { useEffect(() => { - if (activeInstance !== -1) { + if ( + activeInstance !== -1 && + typeof chartType !== 'undefined' && + typeof activeElementType !== 'undefined' + ) { const possibleChartTypes = ACTIVE_CHART_TYPES[activeElementType].map( (type) => type.value ) diff --git a/apps/frontend-manage/src/components/evaluation/navigation/StackNavigation.tsx b/apps/frontend-manage/src/components/evaluation/navigation/StackNavigation.tsx index cf05c31905..476878623a 100644 --- a/apps/frontend-manage/src/components/evaluation/navigation/StackNavigation.tsx +++ b/apps/frontend-manage/src/components/evaluation/navigation/StackNavigation.tsx @@ -123,7 +123,7 @@ function StackNavigation({
- {leaderboardAvailable && ( + {type === 'LiveQuiz' && leaderboardAvailable && ( )} - {feedbacksAvailable && ( + {type === 'LiveQuiz' && feedbacksAvailable && ( <> - {isStep1Shown && ( -
-

- {t('manage.migration.step1Description')} -

- setEmail(newValue)} - className={{ - field: 'w-[500px]', - input: 'w-[500px]', - }} - /> - -
- )} -
- -
- - {isStep2Shown && ( -
-

- {t('manage.migration.step2Description')} -

-
- )} -
- -
- - {isStep3Shown && ( -
-

- {t('manage.migration.step3Description', { - email: data?.userProfile?.email, - })} -

- -
- )} -
- -
- - {isStep4Shown && ( -
-

- {t('manage.migration.step4Description', { - email: data?.userProfile?.email, - })} -

-
- )} -
-
- - ) -} - -export default Migration - -export async function getServerSideProps({ - query, - locale, -}: GetServerSidePropsContext) { - return { - props: { - query, - messages: (await import(`@klicker-uzh/i18n/messages/${locale}`)).default, - }, - } -} diff --git a/apps/frontend-manage/src/pages/qr/[...args].tsx b/apps/frontend-manage/src/pages/qr/[...args].tsx index 92f17ed215..94a2bf1d7a 100644 --- a/apps/frontend-manage/src/pages/qr/[...args].tsx +++ b/apps/frontend-manage/src/pages/qr/[...args].tsx @@ -10,17 +10,24 @@ import { twMerge } from 'tailwind-merge' interface Props { path: string - width: number + width?: number className?: { + root?: string title?: string canvas?: string } + showLink?: boolean + showButton?: boolean + showLogo?: boolean } export function QR({ path, width = 200, className, + showLink = true, + showButton = true, + showLogo = true, }: Props): React.ReactElement { const t = useTranslations() @@ -35,29 +42,46 @@ export function QR({ }, [ref, path]) return ( -
- -
- {process.env.NEXT_PUBLIC_PWA_URL} - {path} -
- +
+ {showLink && ( + +
+ {process.env.NEXT_PUBLIC_PWA_URL} + {path} +
+ + )}
- } - logoHeight={width / 3.34} - logoImage="/img/KlickerLogo.png" - logoWidth={width} - size={width * 3} - value={`${process.env.NEXT_PUBLIC_PWA_URL}${path}`} - /> + {showLogo && width ? ( + } + logoHeight={width / 3.34} + logoImage="/img/KlickerLogo.png" + logoWidth={width} + size={width * 3} + value={`${process.env.NEXT_PUBLIC_PWA_URL}${path}`} + /> + ) : ( + } + style={{ width: '100%', height: '100%' }} + value={`${process.env.NEXT_PUBLIC_PWA_URL}${path}`} + /> + )}
- + {showButton && ( + + )}
) } diff --git a/apps/frontend-manage/src/pages/sessions/[id]/evaluation.tsx b/apps/frontend-manage/src/pages/sessions/[id]/evaluation.tsx index b574595da0..86afd532d1 100644 --- a/apps/frontend-manage/src/pages/sessions/[id]/evaluation.tsx +++ b/apps/frontend-manage/src/pages/sessions/[id]/evaluation.tsx @@ -33,7 +33,12 @@ function Evaluation() { return {t('shared.generic.systemError')} } - if (!data) { + if ( + !data?.liveQuizEvaluation || + !data?.liveQuizLeaderboard || + (data.liveQuizEvaluation.results.length === 0 && + data.liveQuizLeaderboard.length === 0) + ) { return (
{ return { ...participant, @@ -171,8 +172,9 @@ function SuspendedGroupView({ rank: participant.rank ?? 1, level: participant.level ?? 1, } - }) ?? [] - } + }) ?? [], + [prop('rank'), 'asc'] + )} participant={participant} onLeave={ isGroupDeadlinePassed diff --git a/apps/frontend-pwa/src/components/practiceQuiz/ElementSummary.tsx b/apps/frontend-pwa/src/components/practiceQuiz/ElementSummary.tsx deleted file mode 100644 index 0c8b21aa97..0000000000 --- a/apps/frontend-pwa/src/components/practiceQuiz/ElementSummary.tsx +++ /dev/null @@ -1,248 +0,0 @@ -import { useTranslations } from 'next-intl' -import { useRouter } from 'next/router' - -interface ElementSummaryProps { - displayName: string - stacks: any // previously stack type -} - -function ElementSummary({ displayName, stacks }: ElementSummaryProps) { - const t = useTranslations() - const router = useRouter() - const courseId = router.query.courseId as string - - return
- - // const { data: participation } = useQuery(GetParticipationDocument, { - // variables: { - // courseId, - // }, - // }) - - // const { data: participant } = useQuery(SelfDocument) - - // const { totalPointsAwarded, totalXpAwarded } = stacks.reduce<{ - // totalPointsAwarded: number - // totalXpAwarded: number - // }>( - // (acc, stack) => { - // const temp = stack.elements?.reduce<{ - // totalPointsAwarded: number - // totalXpAwarded: number - // }>( - // (acc, element) => { - // return { - // totalPointsAwarded: - // acc.totalPointsAwarded + - // (element.questionInstance?.evaluation?.pointsAwarded ?? 0), - // totalXpAwarded: - // acc.totalPointsAwarded + - // (element.questionInstance?.evaluation?.xpAwarded ?? 0), - // } - // }, - // { totalPointsAwarded: 0, totalXpAwarded: 0 } - // ) - - // return { - // totalPointsAwarded: - // acc.totalPointsAwarded + (temp?.totalPointsAwarded ?? 0), - // totalXpAwarded: acc.totalXpAwarded + (temp?.totalXpAwarded ?? 0), - // } - // }, - // { totalPointsAwarded: 0, totalXpAwarded: 0 } - // ) - - // const gradedStacks = useMemo( - // () => - // stacks - // .filter((stack) => { - // return stack.elements?.some((element) => { - // return element.questionInstance - // }) - // }) - // .map((stack) => { - // return { - // ...stack, - // ...stack.elements - // ?.filter((element) => { - // if (element.mdContent) return - // return element - // }) - // .reduce<{ - // elements: any // previously list of stack elements - // pointsAwarded: number - // xpAwarded: number - // score: number - // pointsPossible: number - // solved: boolean - // }>( - // (acc, element) => { - // if (element.questionInstance) { - // return { - // ...acc, - // elements: [...acc.elements, element], - // pointsAwarded: - // acc.pointsAwarded + - // (element.questionInstance.evaluation?.pointsAwarded ?? - // 0), - // xpAwarded: - // acc.xpAwarded + - // (element.questionInstance.evaluation?.xpAwarded ?? 0), - // score: - // acc.score + - // (element.questionInstance.evaluation?.score ?? 0), - // pointsPossible: - // acc.pointsPossible + - // (element.questionInstance.pointsMultiplier ?? 1) * 10, - // solved: - // acc.solved || - // (typeof element.questionInstance.evaluation !== - // 'undefined' && - // element.questionInstance.evaluation !== null), - // } - // } - // return acc - // }, - // { - // elements: [], - // pointsAwarded: 0, - // xpAwarded: 0, - // score: 0, - // pointsPossible: 0, - // solved: false, - // } - // ), - // } - // }), - // [stacks] - // ) - - // const levelUp = useMemo( - // () => - // levelFromXp(participant?.self?.xp ?? 0) < - // levelFromXp((participant?.self?.xp ?? 0) + totalXpAwarded), - // [participant?.self, totalXpAwarded] - // ) - - // return ( - //
- //
- //

{t('shared.generic.congrats')}

- //

- // {t.rich('pwa.practiceQuiz.solvedPracticeQuiz', { - // name: displayName, - // it: (text) => {text}, - // })} - //

- //
- //
- //
- // {participant?.self && ( - // <> - // Old Level - - // Eating Bubble - - // New Level - // - // )} - //
- // {participant?.self?.levelData?.nextLevel?.requiredXp && ( - // - // )} - // {participant?.self && ( - //
- // {t('pwa.practiceQuiz.totalXp', { - // xp: totalXpAwarded, - // })} - //
- // )} - //
- //
- //
- //

{t('shared.generic.evaluation')}

- //

- // {typeof participation?.getParticipation?.isActive === 'boolean' && - // participation?.getParticipation?.isActive - // ? t('pwa.practiceQuiz.pointsCollectedPossible') - // : t('pwa.practiceQuiz.pointsComputedAvailable')} - //

- //
- //
- // {gradedStacks.map((stack) => ( - //
- //
- // {stack.displayName ?? - // ((stack?.elements?.length || 1) > 1 - // ? `${stack?.elements?.[0].questionInstance?.questionData.name}, ...` - // : `${stack?.elements?.[0].questionInstance?.questionData.name}`)} - //
- // {stack?.solved ? ( - //
- // {participation?.getParticipation?.isActive - // ? `${stack.pointsAwarded} / ` - // : ''}{' '} - // {stack.score} / {stack.pointsPossible} - //
- // ) : ( - //
{t('pwa.practiceQuiz.notAttempted')}
- // )} - //
- // ))} - //
- - // {typeof participation?.getParticipation?.isActive === 'boolean' && - // participation?.getParticipation?.isActive && ( - //

- // {t('pwa.practiceQuiz.totalPoints', { - // points: totalPointsAwarded, - // })} - //

- // )} - // {typeof participation?.getParticipation?.isActive === 'boolean' && - // !participation?.getParticipation?.isActive && ( - // - // {t.rich('pwa.practiceQuiz.inactiveParticipation', { - // it: (text) => {text}, - // name: displayName, - // })} - // - // )} - // {participant?.self && !participation?.getParticipation && ( - // - // {t.rich('pwa.practiceQuiz.missingParticipation', { - // it: (text) => {text}, - // name: displayName, - // })} - // - // )} - //
- //
- // ) -} - -export default ElementSummary diff --git a/apps/frontend-pwa/src/components/practiceQuiz/PracticeQuiz.tsx b/apps/frontend-pwa/src/components/practiceQuiz/PracticeQuiz.tsx index caf317db7c..e746b621e1 100644 --- a/apps/frontend-pwa/src/components/practiceQuiz/PracticeQuiz.tsx +++ b/apps/frontend-pwa/src/components/practiceQuiz/PracticeQuiz.tsx @@ -134,13 +134,6 @@ function PracticeQuiz({ bookmarks={bookmarksData?.getBookmarksPracticeQuiz} /> )} - - {/* {currentIx >= 0 && !currentStack && ( - - )} */}
) diff --git a/apps/func-incoming-responses/package.json b/apps/func-incoming-responses/package.json index 47a7625462..137594eea0 100644 --- a/apps/func-incoming-responses/package.json +++ b/apps/func-incoming-responses/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@klicker-uzh/func-incoming-responses", - "version": "3.3.0-alpha.4", + "version": "3.3.0-alpha.7", "license": "AGPL-3.0", "main": "dist/index.js", "files": [ diff --git a/apps/func-migration-v2-export/.funcignore b/apps/func-migration-v2-export/.funcignore deleted file mode 100644 index 2639b6da22..0000000000 --- a/apps/func-migration-v2-export/.funcignore +++ /dev/null @@ -1,13 +0,0 @@ -*.js.map -*.ts -.git* -.vscode -local.settings.json -test -getting_started.md -node_modules/@types/ -node_modules/azure-functions-core-tools/ -node_modules/typescript/ -__azurite_db*__.json -__blobstorage__ -__queuestorage__ diff --git a/apps/func-migration-v2-export/.gitignore b/apps/func-migration-v2-export/.gitignore deleted file mode 100644 index 99e24b78de..0000000000 --- a/apps/func-migration-v2-export/.gitignore +++ /dev/null @@ -1,101 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# TypeScript v1 declaration files -typings/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test - -# parcel-bundler cache (https://parceljs.org/) -.cache - -# next.js build output -.next - -# nuxt.js build output -.nuxt - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TypeScript output -dist -out - -# Azure Functions artifacts -bin -obj -appsettings.json -local.settings.json - -# Azurite artifacts -__blobstorage__ -__queuestorage__ -__azurite_db*__.json - -src/**.js diff --git a/apps/func-migration-v2-export/host.json b/apps/func-migration-v2-export/host.json deleted file mode 100644 index 8238e7f905..0000000000 --- a/apps/func-migration-v2-export/host.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "version": "2.0", - "watchDirectories": ["dist"], - "logging": { - "fileLoggingMode": "always", - "logLevel": { - "default": "Warning", - "Function.MigrationV2Export": "Information" - }, - "applicationInsights": { - "samplingSettings": { - "isEnabled": true, - "excludedTypes": "Request" - } - } - }, - "extensionBundle": { - "id": "Microsoft.Azure.Functions.ExtensionBundle", - "version": "[3.15.0, 4.0.0)" - }, - "concurrency": { - "dynamicConcurrencyEnabled": true, - "snapshotPersistenceEnabled": true - } -} diff --git a/apps/func-migration-v2-export/local.settings.template b/apps/func-migration-v2-export/local.settings.template deleted file mode 100644 index 1343126ff0..0000000000 --- a/apps/func-migration-v2-export/local.settings.template +++ /dev/null @@ -1,20 +0,0 @@ -{ - "IsEncrypted": false, - "Values": { - "NODE_ENV": "development", - "AzureWebJobsStorage": "UseDevelopmentStorage=true", - "FUNCTIONS_WORKER_RUNTIME": "node", - "FUNCTIONS_EXTENSION_VERSION": "~4", - "FUNCTIONS_WORKER_PROCESS_COUNT": 10, - "AzureWebJobsFeatureFlags": "EnableWorkerIndexing", - "MIGRATION_SERVICE_BUS_CONNECTION_STRING": "", - "MIGRATION_SERVICE_BUS_QUEUE_NAME": "", - "MIGRATION_BLOB_EXPORT_CONNECTION_STRING": "", - "MIGRATION_BLOB_STORAGE_PATH": "", - "MIGRATION_MONGO_CONNECTION_STRING": "", - "LISTMONK_USER": "", - "LISTMONK_PASS": "", - "LISTMONK_URL": "", - "LISTMONK_TEMPLATE_MIGRATION_RUNNING_SESSION": -1 - } -} diff --git a/apps/func-migration-v2-export/package.json b/apps/func-migration-v2-export/package.json deleted file mode 100644 index 359305259b..0000000000 --- a/apps/func-migration-v2-export/package.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "private": true, - "name": "@klicker-uzh/func-migration-v2-export", - "version": "3.3.0-alpha.4", - "license": "AGPL-3.0", - "main": "dist/index.js", - "files": [ - "dist/" - ], - "dependencies": { - "@azure/functions": "4.5.1", - "@azure/storage-blob": "12.25.0", - "axios": "1.7.7", - "jsonwebtoken": "9.0.2", - "mongodb": "5.7.0" - }, - "devDependencies": { - "@types/jsonwebtoken": "^9.0.7", - "@types/node": "^20.16.1", - "azure-functions-core-tools": "~4.0.6280", - "cross-env": "~7.0.3", - "eslint": "~8.45.0", - "npm-run-all": "~4.1.5", - "tsup": "~8.3.0", - "typescript": "~5.6.3" - }, - "scripts": { - "build": "cross-env NODE_ENV=production tsup", - "check": "tsc --noEmit", - "dev:func": "func start -p 7074 --verbose --javascript", - "dev:migration": "npm-run-all --parallel dev:ts dev:func", - "dev:ts": "tsup --watch", - "prestart": "pnpm run build", - "start": "func start -p 7074" - }, - "engines": { - "node": "=20" - }, - "volta": { - "extends": "../../package.json" - } -} diff --git a/apps/func-migration-v2-export/src/blob.ts b/apps/func-migration-v2-export/src/blob.ts deleted file mode 100644 index bb4050a8e6..0000000000 --- a/apps/func-migration-v2-export/src/blob.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { InvocationContext } from '@azure/functions' -import { BlobServiceClient, ContainerClient } from '@azure/storage-blob' - -let blobClient: ContainerClient - -async function getBlobClient(context: InvocationContext) { - if (!blobClient) { - try { - const blobServiceClient = new BlobServiceClient( - process.env.MIGRATION_BLOB_EXPORT_CONNECTION_STRING as string - ) - - blobClient = blobServiceClient.getContainerClient('exports') - } catch (e) { - context.error(e) - } - } - - return blobClient -} - -export default getBlobClient diff --git a/apps/func-migration-v2-export/src/index.ts b/apps/func-migration-v2-export/src/index.ts deleted file mode 100644 index d71495f8fe..0000000000 --- a/apps/func-migration-v2-export/src/index.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { app, InvocationContext } from '@azure/functions' -import getBlobClient from './blob' -import getMongoDB from './mongo' -import { sendTeamsNotifications } from './utils' - -interface Message { - messageId: string - newUserId: string - newEmail: string - originalEmail: string -} - -const serviceBusTrigger = async function ( - message: any, - context: InvocationContext -) { - context.log('MigrationV2Export function processing a message', message) - - try { - const messageData = message as Message - - await sendTeamsNotifications( - 'func/migration-v2-export', - `Started export of KlickerV2 data for '${messageData.originalEmail}' -> '${messageData.newEmail}'`, - context - ) - - const db = await getMongoDB(context) - - const matchingUsers = await db - .collection('users') - .find({ email: messageData.originalEmail.toLowerCase() }) - .toArray() - - if (!matchingUsers?.[0]) { - throw new Error( - `No matching V2 user found for ${messageData.originalEmail}` - ) - } - - const matchingUser = matchingUsers[0] - - const exportData: Record = { - user_id: matchingUser._id.toString(), - user_email: matchingUser.email, - sessions: [], - tags: [], - questions: [], - questioninstances: [], - files: [], - } - - for (const collectionName of [ - 'sessions', - 'tags', - 'questions', - 'questioninstances', - 'files', - ]) { - const documents = await db - .collection(collectionName) - .find({ user: matchingUser._id }) - .toArray() - - exportData[collectionName] = documents - - context.log( - `Fetched ${documents.length} documents from collection '${collectionName}' for user '${matchingUser.email}'.` - ) - } - - exportData.questions = exportData.questions.map((question: any) => { - if (question.versions) { - question.versions = question.versions[question.versions.length - 1] - } - - return question - }) - - const blobClient = await getBlobClient(context) - - const blockBlobClient = blobClient.getBlockBlobClient( - `${messageData.newUserId}_${Date.now()}.json` - ) - - await blockBlobClient.uploadData(Buffer.from(JSON.stringify(exportData)), { - blockSize: 4 * 1024 * 1024, // 4MB block size - }) - - await sendTeamsNotifications( - 'func/migration-v2-export', - `Successful export for user '${messageData.originalEmail}' (${messageData.newEmail})`, - context - ) - - return exportData - } catch (e) { - context.error('Something went wrong while exporting data: ', e) - - await sendTeamsNotifications( - 'func/migration-v2-export', - `Export of KlickerV2 data failed. Error: ${e.message}`, - context - ) - - throw new Error('Something went wrong while exporting data') - } -} - -export default serviceBusTrigger - -app.serviceBusQueue('MigrationV2Export', { - connection: 'MIGRATION_SERVICE_BUS_CONNECTION_STRING', - queueName: process.env.MIGRATION_SERVICE_BUS_QUEUE_NAME as string, - handler: serviceBusTrigger, -}) diff --git a/apps/func-migration-v2-export/src/mongo.ts b/apps/func-migration-v2-export/src/mongo.ts deleted file mode 100644 index 84e24ca1c3..0000000000 --- a/apps/func-migration-v2-export/src/mongo.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { InvocationContext } from '@azure/functions' -import { Db, MongoClient } from 'mongodb' - -let mongo: Db - -async function getMongoDB(context: InvocationContext) { - if (!mongo) { - try { - const mongoURL = process.env.MIGRATION_MONGO_CONNECTION_STRING as string - - const mongoClient = new MongoClient(mongoURL) - await mongoClient.connect() - - mongo = mongoClient.db('klicker-prod') - } catch (e) { - context.error(e) - } - } - - return mongo -} - -export default getMongoDB diff --git a/apps/func-migration-v2-export/src/utils.ts b/apps/func-migration-v2-export/src/utils.ts deleted file mode 100644 index 0e64eeef52..0000000000 --- a/apps/func-migration-v2-export/src/utils.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { InvocationContext } from '@azure/functions' -import axios from 'axios' - -export function sliceIntoChunks(array: any[], chunkSize: number) { - const result = [] - let index = 0 - while (index < array.length) { - result.push(array.slice(index, index + chunkSize)) - index += chunkSize - } - return result -} - -export async function sendTeamsNotifications( - scope: string, - text: string, - context: InvocationContext -) { - if (process.env.TEAMS_WEBHOOK_URL) { - try { - return axios.post(process.env.TEAMS_WEBHOOK_URL, { - '@context': 'https://schema.org/extensions', - '@type': 'MessageCard', - themeColor: '0076D7', - title: `Migration: ${scope}`, - text: `[${process.env.NODE_ENV}:${scope}] ${text}`, - }) - } catch (e) { - context.error(e) - } - } - - return null -} diff --git a/apps/func-migration-v2-export/tsconfig.json b/apps/func-migration-v2-export/tsconfig.json deleted file mode 100644 index e7462b19eb..0000000000 --- a/apps/func-migration-v2-export/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es6", - "outDir": "dist", - "rootDir": ".", - "sourceMap": true, - "strict": false, - "skipLibCheck": true - } -} diff --git a/apps/func-migration-v2-export/tsup.config.ts b/apps/func-migration-v2-export/tsup.config.ts deleted file mode 100644 index dce074b044..0000000000 --- a/apps/func-migration-v2-export/tsup.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'tsup' - -export default defineConfig({ - entry: ['src/index.ts'], - clean: true, - noExternal: [/@klicker-uzh.*/], -}) diff --git a/apps/func-migration-v3-import/.funcignore b/apps/func-migration-v3-import/.funcignore deleted file mode 100644 index 2639b6da22..0000000000 --- a/apps/func-migration-v3-import/.funcignore +++ /dev/null @@ -1,13 +0,0 @@ -*.js.map -*.ts -.git* -.vscode -local.settings.json -test -getting_started.md -node_modules/@types/ -node_modules/azure-functions-core-tools/ -node_modules/typescript/ -__azurite_db*__.json -__blobstorage__ -__queuestorage__ diff --git a/apps/func-migration-v3-import/.gitignore b/apps/func-migration-v3-import/.gitignore deleted file mode 100644 index 1df4e88473..0000000000 --- a/apps/func-migration-v3-import/.gitignore +++ /dev/null @@ -1,102 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# TypeScript v1 declaration files -typings/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test - -# parcel-bundler cache (https://parceljs.org/) -.cache - -# next.js build output -.next - -# nuxt.js build output -.nuxt - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TypeScript output -dist -out - -# Azure Functions artifacts -bin -obj -appsettings.json -local.settings.json - -# Azurite artifacts -__blobstorage__ -__queuestorage__ -__azurite_db*__.json - -src/**.js -src/client/ diff --git a/apps/func-migration-v3-import/host.json b/apps/func-migration-v3-import/host.json deleted file mode 100644 index c8fbcca7f9..0000000000 --- a/apps/func-migration-v3-import/host.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "version": "2.0", - "watchDirectories": ["dist"], - "logging": { - "fileLoggingMode": "always", - "logLevel": { - "default": "Warning", - "Function.MigrationV3Import": "Information" - }, - "applicationInsights": { - "samplingSettings": { - "isEnabled": true, - "excludedTypes": "Request" - } - } - }, - "extensionBundle": { - "id": "Microsoft.Azure.Functions.ExtensionBundle", - "version": "[3.15.0, 4.0.0)" - }, - "concurrency": { - "dynamicConcurrencyEnabled": true, - "snapshotPersistenceEnabled": true - }, - "extensions": { - "blobs": { - "maxDequeueCount": 1 - }, - "queues": { - "maxDequeueCount": 1 - } - }, - "functionTimeout": "00:10:00" -} diff --git a/apps/func-migration-v3-import/local.settings.template b/apps/func-migration-v3-import/local.settings.template deleted file mode 100644 index 4d750eedff..0000000000 --- a/apps/func-migration-v3-import/local.settings.template +++ /dev/null @@ -1,20 +0,0 @@ -{ - "IsEncrypted": false, - "Values": { - "NODE_ENV": "development", - "AzureWebJobsStorage": "UseDevelopmentStorage=true", - "FUNCTIONS_WORKER_RUNTIME": "node", - "FUNCTIONS_EXTENSION_VERSION": "~4", - "FUNCTIONS_WORKER_PROCESS_COUNT": 10, - "AzureWebJobsFeatureFlags": "EnableWorkerIndexing", - "MIGRATION_BLOB_IMPORT_CONNECTION_STRING": "", - "MIGRATION_BLOB_IMPORT_IMAGES_CONNECTION_STRING": "", - "MIGRATION_LEGACY_MONGO_CONNECTION_STRING": "", - "TEAMS_WEBHOOK_URL": "", - "LISTMONK_USER": "", - "LISTMONK_PASS": "", - "LISTMONK_URL": "", - "LISTMONK_TEMPLATE_MIGRATION_SUCCESS": -1, - "LISTMONK_TEMPLATE_MIGRATION_FAILURE": -1 - } -} diff --git a/apps/func-migration-v3-import/package.json b/apps/func-migration-v3-import/package.json deleted file mode 100644 index b222fa115c..0000000000 --- a/apps/func-migration-v3-import/package.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "private": true, - "name": "@klicker-uzh/func-migration-v3-import", - "version": "3.3.0-alpha.4", - "license": "AGPL-3.0", - "main": "dist/index.js", - "files": [ - "dist/" - ], - "dependencies": { - "@azure/functions": "4.5.1", - "@azure/storage-blob": "12.25.0", - "@klicker-uzh/prisma": "workspace:*", - "axios": "1.7.7", - "jsonwebtoken": "9.0.2", - "mongoose": "7.3.3", - "uuid": "10.0.0" - }, - "devDependencies": { - "@types/jsonwebtoken": "^9.0.7", - "@types/node": "^20.16.1", - "@types/uuid": "^10.0.0", - "azure-functions-core-tools": "~4.0.6280", - "cross-env": "~7.0.3", - "eslint": "~8.45.0", - "npm-run-all": "~4.1.5", - "prisma": "~5.21.0", - "tsup": "~8.3.0", - "tsx": "~4.19.1", - "typescript": "~5.6.3" - }, - "scripts": { - "build": "cross-env NODE_ENV=production tsup", - "check": "tsc --noEmit", - "dev:copy": "tsx src/copy.ts", - "dev:func": "func start -p 7075 --verbose --javascript", - "dev:function": "run-p dev:func dev:ts", - "dev:migration": "run-s dev:copy dev:function", - "dev:ts": "tsup --watch", - "prestart": "pnpm run build", - "start": "func start -p 7075" - }, - "engines": { - "node": "=20" - }, - "volta": { - "extends": "../../package.json" - } -} diff --git a/apps/func-migration-v3-import/src/blob.ts b/apps/func-migration-v3-import/src/blob.ts deleted file mode 100644 index 262ad1603d..0000000000 --- a/apps/func-migration-v3-import/src/blob.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { InvocationContext } from '@azure/functions' -import { BlobServiceClient } from '@azure/storage-blob' - -async function getBlobClient(context: InvocationContext, userId: string) { - const blobServiceClient = new BlobServiceClient( - process.env.MIGRATION_BLOB_IMPORT_IMAGES_CONNECTION_STRING as string - ) - - const containerClient = blobServiceClient.getContainerClient(userId) - - if (!(await containerClient.exists())) { - await containerClient.create({ - access: 'blob', - }) - } - - return containerClient -} - -export default getBlobClient diff --git a/apps/func-migration-v3-import/src/copy.ts b/apps/func-migration-v3-import/src/copy.ts deleted file mode 100644 index 83bfcba6e6..0000000000 --- a/apps/func-migration-v3-import/src/copy.ts +++ /dev/null @@ -1,12 +0,0 @@ -import * as fs from 'fs' - -try { - fs.rmdirSync('./dist', { recursive: true }) -} catch (e) {} - -fs.mkdirSync('./dist/') - -fs.copyFileSync( - '../../packages/prisma/dist/schema.prisma', - './dist/schema.prisma' -) diff --git a/apps/func-migration-v3-import/src/getLegacyResults.ts b/apps/func-migration-v3-import/src/getLegacyResults.ts deleted file mode 100644 index 6625180731..0000000000 --- a/apps/func-migration-v3-import/src/getLegacyResults.ts +++ /dev/null @@ -1,68 +0,0 @@ -import mongoose from 'mongoose' - -const { Schema, Types } = mongoose -const { ObjectId } = Types - -const Response = new mongoose.Schema( - { - participant: { type: String, ref: 'SessionParticipant' }, - value: { type: Object, required: true }, - }, - { timestamps: true } -) - -const Results = new mongoose.Schema( - { - CHOICES: [{ type: Number }], - FREE: { type: Object }, - totalParticipants: { type: Number, default: 0 }, - }, - { timestamps: true } -) - -const LegacyQuestionInstance = new mongoose.Schema( - { - isOpen: { type: Boolean, default: false }, - question: { type: ObjectId, ref: 'Question', required: true, index: true }, - session: { type: ObjectId, ref: 'Session', required: true, index: true }, - user: { type: ObjectId, ref: 'User', required: true, index: true }, - version: { type: Number, min: 0, required: true }, - blockedParticipants: [{ type: String }], - responses: [{ type: Response }], - dropped: [{ type: Response }], - results: { type: Results }, - }, - { timestamps: true } -) - -LegacyQuestionInstance.index({ '$**': 1 }) - -const legacyConnection = mongoose.createConnection( - process.env.MIGRATION_LEGACY_MONGO_CONNECTION_STRING as string, - { - dbName: 'klicker-prod', - authSource: 'admin', - keepAlive: true, - } -) - -process.on('SIGINT', function () { - legacyConnection.close() -}) - -const LegacyQuestionInstanceModel = legacyConnection.model( - 'LegacyQuestionInstance', - LegacyQuestionInstance, - 'questioninstances' -) - -export async function getLegacyResults(legacyQuestionInstanceId: string) { - const legacyInstance = await LegacyQuestionInstanceModel.findById( - new ObjectId(legacyQuestionInstanceId) - ) - return legacyInstance ? legacyInstance.results : null -} - -export function closeLegacyConnection() { - legacyConnection.close() -} diff --git a/apps/func-migration-v3-import/src/importQuestionInstances.ts b/apps/func-migration-v3-import/src/importQuestionInstances.ts deleted file mode 100644 index 10693f3290..0000000000 --- a/apps/func-migration-v3-import/src/importQuestionInstances.ts +++ /dev/null @@ -1,211 +0,0 @@ -import { InvocationContext } from '@azure/functions' -import { PrismaClient, QuestionInstanceType } from '@klicker-uzh/prisma' -import { getLegacyResults } from './getLegacyResults' -import { - QuestionTypeMap, - sendTeamsNotifications, - sliceIntoChunks, -} from './utils' - -export const importQuestionInstances = async ( - prisma: PrismaClient, - importedQuestionInstances: any, - mappedQuestionIds: Record, - user, - batchSize: number, - context: InvocationContext -) => { - try { - let mappedQuestionInstancesIds: Record = {} - const questions = await prisma.element.findMany({ - where: { - id: { - in: Object.values(mappedQuestionIds), - }, - owner: { - id: user.id, - }, - }, - }) - const questionInstancesInDb = await prisma.questionInstance.findMany({ - where: { - originalId: { - not: null, - }, - owner: { - id: user.id, - }, - }, - }) - const questionInstancesDict: Record = - questionInstancesInDb.reduce( - (acc, qi) => ({ - ...acc, - [qi.originalId]: qi, - }), - {} - ) - - const batches = sliceIntoChunks(importedQuestionInstances, 10) - let lostResults: any[] = [] - - for (const batch of batches) { - const preparedQuestionInstances = ( - await Promise.allSettled( - batch.map(async (questionInstance) => { - const questionInstanceExists = - questionInstancesDict[questionInstance._id] - - if (questionInstanceExists) { - mappedQuestionInstancesIds[questionInstance._id] = - questionInstanceExists.id - return null - } - - let questionData: any = {} - let questionId = null - const question = questions.find( - (question) => - question.id === mappedQuestionIds[questionInstance.question] - ) - - if (question) { - questionId = question.id - questionData = { - ...question, - id: `${questionId}-v1`, - questionId, - } - } - - if ( - questionInstance.results && - !questionInstance.results.CHOICES && - !questionInstance.results.FREE - ) { - questionInstance.results = await getLegacyResults( - questionInstance._id - ) - if (questionInstance.results == null) { - lostResults.push(questionInstance) - } - } - - let results = {} - - if (question && questionInstance.results) { - if (questionData.type === 'SC' || questionData.type === 'MC') { - if (questionInstance.results.CHOICES) { - results = questionInstance.results.CHOICES.reduce( - (acc, choice, idx) => { - acc[idx.toString()] = { - count: choice, - value: idx.toString(), - } - return acc - }, - {} - ) - } - } else if ( - questionData.type === QuestionTypeMap['FREE'] || - questionData.type === QuestionTypeMap['FREE_RANGE'] - ) { - if (questionInstance.results.FREE) { - let newResults = Object.keys( - questionInstance.results.FREE - ).reduce((acc, hash) => { - acc[hash] = questionInstance.results.FREE[hash] - return acc - }, {}) - results = { ...results, ...newResults } - } else if (questionInstance.results.FREE_RANGE) { - let newResults = Object.keys( - questionInstance.results.FREE_RANGE - ).reduce((acc, hash) => { - acc[hash] = questionInstance.results.FREE_RANGE[hash] - return acc - }, {}) - results = { ...results, ...newResults } - } - } - } - - return { - originalId: questionInstance._id, - type: QuestionInstanceType.SESSION, - questionData: questionData, - participants: questionInstance.results?.totalParticipants, - results: results, - owner: { - connect: { - id: user.id, - }, - }, - question: questionId - ? { - connect: { - id: questionId, - }, - } - : undefined, - createdAt: new Date(questionInstance.createdAt), - updatedAt: new Date(questionInstance.updatedAt), - } - }) - ) - ).flatMap((result) => { - if (result.status === 'fulfilled') { - if (result.value !== null) { - return [result.value] - } - } - return [] - }) - - await Promise.all( - preparedQuestionInstances.map((questionInstance) => - prisma.$transaction(async (prisma) => { - const newQuestionInstance = await prisma.questionInstance.create({ - data: questionInstance, - }) - - mappedQuestionInstancesIds[questionInstance.originalId] = - newQuestionInstance.id - - if (questionInstance.questionData.id) { - await prisma.element.update({ - where: { - id: questionInstance.questionData.questionId, - }, - data: { - instances: { - connect: { - id: newQuestionInstance.id, - }, - }, - }, - }) - } - }) - ) - ) - } - - context.log('mappedQuestionInstancesIds', mappedQuestionInstancesIds) - - context.log('lostResults.length: ', lostResults.length) - return mappedQuestionInstancesIds - } catch (error) { - context.error( - 'Something went wrong while importing question instances: ', - error - ) - await sendTeamsNotifications( - 'func/migration-v3-import', - `Failed migration of question instances for user '${user.email}' because of ${error}`, - context - ) - throw error - } -} diff --git a/apps/func-migration-v3-import/src/importQuestions.ts b/apps/func-migration-v3-import/src/importQuestions.ts deleted file mode 100644 index 55ed4e95de..0000000000 --- a/apps/func-migration-v3-import/src/importQuestions.ts +++ /dev/null @@ -1,181 +0,0 @@ -import { InvocationContext } from '@azure/functions' -import { PrismaClient } from '@klicker-uzh/prisma' -import { - QuestionTypeMap, - sendTeamsNotifications, - sliceIntoChunks, -} from './utils' - -export const importQuestions = async ( - prisma: PrismaClient, - importedQuestions: any, - mappedTags: Record>, - user, - batchSize: number, - mappedFileURLs: Record>, - context: InvocationContext -) => { - try { - let mappedQuestionIds: Record = {} - const questionsInDb = await prisma.element.findMany({ - where: { - originalId: { - not: null, - }, - owner: { - id: user.id, - }, - }, - }) - - const questionsDict: Record = questionsInDb.reduce( - (acc, cur) => ({ - ...acc, - [cur.originalId]: cur, - }), - {} - ) - - const batches = sliceIntoChunks(importedQuestions, 20) - - for (const batch of batches) { - const preparedQuestions = batch.flatMap((question) => { - const questionExists = questionsDict[question._id] - - if (questionExists) { - mappedQuestionIds[question._id] = questionExists.id - return [] - } - - const result = { - data: { - originalId: question._id, - name: question.title, - type: QuestionTypeMap[question.type], - content: - question.versions.content + - (question.versions.files?.length > 0 - ? '\n' + - question.versions.files - .map( - (fileId: string) => - `![${mappedFileURLs[fileId].originalName}](${mappedFileURLs[fileId].url})` - ) - .join('\n\n') + - '\n' - : ''), - options: { - displayMode: - question.type == 'SC' || question.type == 'MC' - ? 'LIST' - : undefined, - hasSampleSolution: false, - hasAnswerFeedbacks: false, - choices: undefined, - restrictions: undefined, - solutions: undefined, - solutionRanges: undefined, - }, - isDeleted: question.isDeleted, - isArchived: question.isArchived, - tags: { - connect: question.tags.flatMap((oldTagId) => { - if (!mappedTags[oldTagId]) { - context.log('Tag not found: ', oldTagId) - return [] - } - const tagName = mappedTags[oldTagId].name - return [ - { - ownerId_name: { - ownerId: user.id, - name: tagName, - }, - }, - ] - }), - }, - owner: { - connect: { - id: user.id, - }, - }, - createdAt: new Date(question.createdAt), - updatedAt: new Date(question.updatedAt), - }, - } - - if (['SC', 'MC'].includes(question.type)) { - result.data.options = { - ...result.data.options, - hasSampleSolution: question.versions.options[ - question.type - ].choices.some((choice) => choice.correct), - choices: question.versions.options[question.type].choices.map( - (choice, ix) => { - return { - ix, - value: choice.name, - correct: choice.correct, - feedback: '', - } - } - ), - } - } else if (question.type === 'FREE_RANGE') { - // throw new Error('Unsupported question type NR') - const restrictions = - question.versions.options.FREE_RANGE?.restrictions - if (!restrictions) { - result.data.options = { - ...result.data.options, - restrictions: undefined, - solutions: [], - solutionRanges: [], - } - } else { - result.data.options = { - ...result.data.options, - restrictions: { - min: restrictions.min !== null ? restrictions.min : undefined, - max: restrictions.max !== null ? restrictions.max : undefined, - }, - solutions: [], - solutionRanges: [], - } - } - } else if (question.type === 'FREE') { - result.data.options = { - ...result.data.options, - restrictions: {}, - solutions: [], - } - } else { - return [] - } - - return [result] - }) - - const createdQuestions = await prisma.$transaction( - preparedQuestions.map((data) => prisma.element.create(data)) - ) - - createdQuestions.forEach((question) => { - mappedQuestionIds[question.originalId] = question.id - }) - } - - context.log('mappedQuestionIds: ', mappedQuestionIds) - - return mappedQuestionIds - } catch (error) { - context.error('Something went wrong while importing questions: ', error) - await sendTeamsNotifications( - 'func/migration-v3-import', - `Failed migration of questions for user '${user.email}' because of ${error}`, - context - ) - throw error - } -} diff --git a/apps/func-migration-v3-import/src/importSessions.ts b/apps/func-migration-v3-import/src/importSessions.ts deleted file mode 100644 index 74b5d5509b..0000000000 --- a/apps/func-migration-v3-import/src/importSessions.ts +++ /dev/null @@ -1,271 +0,0 @@ -import { InvocationContext } from '@azure/functions' -import { - AccessMode, - PrismaClient, - SessionBlockStatus, - SessionStatus, -} from '@klicker-uzh/prisma' -import { sendTeamsNotifications, sliceIntoChunks } from './utils' - -const getSessionBlockStatus = (status: string) => { - switch (status) { - case 'PLANNED': - return SessionBlockStatus.SCHEDULED - case 'ACTIVE': - return SessionBlockStatus.ACTIVE - case 'EXECUTED': - return SessionBlockStatus.EXECUTED - } -} - -const getSessionStatus = (status: string) => { - switch (status) { - case 'CREATED': - return SessionStatus.PREPARED - case 'COMPLETED': - return SessionStatus.COMPLETED - default: - return null - } -} - -export const importSessions = async ( - prisma: PrismaClient, - importedSessions: any, - mappedQuestionInstanceIds: Record, - user, - batchSize: number, - context: InvocationContext -) => { - try { - //new uuid is generated for each session -> string - let mappedSessionIds: Record = {} - const sessionsInDb = await prisma.liveSession.findMany({ - where: { - originalId: { - not: null, - }, - owner: { - id: user.id, - }, - }, - }) - const sessionsDict: Record = sessionsInDb.reduce((acc, s) => { - if (s.originalId != null) { - acc[s.originalId] = s - } - return acc - }, {}) - - const batches = sliceIntoChunks(importedSessions, 10) - - for (const batch of batches) { - const preparedSessions = batch.flatMap((session) => { - const sessionExists = sessionsDict[session._id] - - // ignore all sessions that are neither created nor completed - const sessionStatus = getSessionStatus(session.status) - if (!sessionStatus) { - return [] - } - - return [ - { - sessionExists, - originalData: session, - prismaData: { - data: { - originalId: session._id, - namespace: session.namespace, - name: session.name, - displayName: session.name, // no displayName in v2 - accessMode: session.settings.isParticipantAuthenticationEnabled - ? AccessMode.RESTRICTED - : AccessMode.PUBLIC, - isConfusionFeedbackEnabled: - session.settings.isConfusionBarometerActive, - isLiveQAEnabled: session.settings.isFeedbackChannelActive, - isModerationEnabled: !session.settings.isFeedbackChannelPublic, - status: sessionStatus, // imported sessions will either be prepared or completed (no active or paused sessions) - createdAt: new Date(session.createdAt), - updatedAt: new Date(session.updatedAt), - startedAt: session.startedAt - ? new Date(session.startedAt) - : null, - finishedAt: session.finishedAt - ? new Date(session.finishedAt) - : null, - // activeBlock: difference 0 and -1? e.g., -1 == nicht gestartet and 0 is first element of list? -->!! null? da keine session "running" sein wird - // blocks: check SessionBlock -> activeInSession ?? --> NO active sessions will be imported! - // no activeSteps in v3 -> sessions will either be prepared or completed - // no activeInstances: QuestionInstance[] in v3 kein link da nichts mehr aktiv sein wird: sessions will either be prepared or completed - // activeInstances? only one possible in v3? kein link da nichts mehr aktiv sein wird: sessions will either be prepared or completed - owner: { - connect: { - id: user.id, - }, - }, - // nested writes for entities that have not circular dependencies - feedbacks: !!session.isBeta - ? { - create: session.feedbacks.map((feedback) => ({ - content: feedback.content, - votes: feedback.votes, - createdAt: new Date(feedback.createdAt), - })), - } - : { - create: session.feedbacks.map((feedback) => ({ - isPublished: feedback.published, - isPinned: feedback.pinned, - isResolved: feedback.resolved, - votes: feedback.votes, - content: feedback.content, - responses: { - create: feedback.responses?.map((response) => ({ - content: response.content, - positiveReactions: response.positiveReactions, - negativeReactions: response.negativeReactions, - createdAt: new Date(response.createdAt), - updatedAt: new Date(response.updatedAt), - })), - }, - createdAt: new Date(feedback.createdAt), - updatedAt: new Date(feedback.updatedAt), - })), - }, - confusionFeedbacks: { - create: session.confusionTS.map((confusionFeedback) => ({ - difficulty: confusionFeedback.difficulty, - speed: confusionFeedback.speed, - createdAt: new Date(confusionFeedback.createdAt), - })), - }, - blocks: { - create: session.blocks.map((sessionBlock, blockIx) => { - const instances = sessionBlock.instances.map( - (instanceId) => ({ - id: mappedQuestionInstanceIds[instanceId], - }) - ) - - return { - originalId: sessionBlock._id, - order: blockIx, - randomSelection: - sessionBlock.randomSelection !== -1 - ? sessionBlock.randomSelection - : null, - timeLimit: - sessionBlock.timeLimit !== -1 - ? sessionBlock.timeLimit - : null, - execution: - sessionBlock.execution !== -1 - ? sessionBlock.execution - : 0, - status: getSessionBlockStatus(sessionBlock.status), - instances: { - connect: instances, - }, - createdAt: new Date(sessionBlock.createdAt), - updatedAt: new Date(sessionBlock.updatedAt), - } - }), - }, - }, - include: { - blocks: { - include: { - instances: true, - }, - }, - }, - }, - }, - ] - }) - - await Promise.allSettled( - preparedSessions.map( - async ({ sessionExists, originalData, prismaData }) => { - return prisma.$transaction(async (prisma) => { - const createdSession = sessionExists - ? await prisma.liveSession.update({ - where: { - id: sessionExists.id, - }, - data: prismaData.data, - include: { - blocks: { - include: { - instances: true, - }, - }, - }, - }) - : await prisma.liveSession.create({ - data: prismaData.data, - include: { - blocks: { - include: { - instances: true, - }, - }, - }, - }) - mappedSessionIds[createdSession.originalId] = createdSession.id - - // Update sessionBlockId of each QuestionInstance connected to the newly created SessionBlock and restore ordering of QuestionInstances - for (const block of createdSession.blocks) { - if (!block || !block.instances) { - continue // skip to the next iteration if there are no instances - } - - const reducedOldBlocks = originalData.blocks.reduce( - (acc, block) => { - acc[block._id] = block - return acc - }, - {} - ) - - for (const instance of block.instances) { - const oldBlock = reducedOldBlocks[block.originalId] - const i = oldBlock?.instances?.findIndex( - (id) => id === instance.originalId - ) - - let updateData = { - sessionBlockId: block.id, - } - - if (i || i === 0) { - updateData['order'] = i - } - - await prisma.questionInstance.update({ - where: { id: instance.id }, - data: updateData, - }) - } - } - }) - } - ) - ) - } - - context.log('mappedSessionIds', mappedSessionIds) - - return mappedSessionIds - } catch (error) { - context.error('Something went wrong while importing sessions: ', error) - await sendTeamsNotifications( - 'func/migration-v3-import', - `Failed migration of sessions for user '${user.email}' because of ${error}`, - context - ) - throw error - } -} diff --git a/apps/func-migration-v3-import/src/importTags.ts b/apps/func-migration-v3-import/src/importTags.ts deleted file mode 100644 index a54d094f0b..0000000000 --- a/apps/func-migration-v3-import/src/importTags.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { InvocationContext } from '@azure/functions' -import { PrismaClient } from '@klicker-uzh/prisma' -import { sendTeamsNotifications, sliceIntoChunks } from './utils' - -export async function importTags( - prisma: PrismaClient, - tags: any, - user, - batchSize: number, - context: InvocationContext -) { - try { - let mappedTags: Record> = {} - const tagsInDb = await prisma.tag.findMany({ - where: { - originalId: { - not: null, - }, - owner: { - id: user.id, - }, - }, - }) - const tagsDict: Record = tagsInDb.reduce( - (acc, t) => ({ - ...acc, - [t.originalId]: t, - }), - {} - ) - const tagsNameDict: Record = tagsInDb.reduce( - (acc, t) => ({ - ...acc, - [t.name]: t, - }), - {} - ) - - const batches = sliceIntoChunks(tags, 20) - - for (const batch of batches) { - const preparedTags = batch.flatMap((tag) => { - const tagExistsById = tagsDict[tag._id] - const tagExistsByName = tagsNameDict[tag.name] - - if (tagExistsById) { - mappedTags[tag._id] = { - id: tagExistsById.id, - name: tagExistsById.name, - } - return [] - } - - if (tagExistsByName) { - mappedTags[tag._id] = { - id: tagExistsByName.id, - name: tagExistsByName.name, - } - return [] - } - - return [ - { - where: { - ownerId_name: { - ownerId: user.id, - name: tag.name, - }, - }, - update: {}, - create: { - name: tag.name, - originalId: tag._id, - owner: { - connect: { - id: user.id, - }, - }, - createdAt: new Date(tag.createdAt), - updatedAt: new Date(tag.updatedAt), - }, - }, - ] - }) - - const migratedTags = await prisma.$transaction( - preparedTags.map((data) => prisma.tag.upsert(data)) - ) - - migratedTags.forEach((tag) => { - mappedTags[tag.originalId] = { id: tag.id, name: tag.name } - }) - } - - context.log('mappedTags: ', mappedTags) - - const userWithTags = await prisma.user.findUnique({ - where: { - id: user.id, - }, - select: { - tags: { - orderBy: { - name: 'asc', - }, - }, - }, - }) - - const [orderedTags, totalTags] = await prisma.$transaction( - userWithTags.tags.map((tag, index) => - prisma.tag.update({ - where: { - id: tag.id, - }, - data: { - order: index, - }, - }) - ) - ) - - console.log('ordered tags: ', orderedTags) - - return mappedTags - } catch (error) { - context.error('Something went wrong while importing tags: ', error) - await sendTeamsNotifications( - 'func/migration-v3-import', - `Failed migration of tags for user '${user.email}' because of ${error}`, - context - ) - throw error - } -} diff --git a/apps/func-migration-v3-import/src/index.ts b/apps/func-migration-v3-import/src/index.ts deleted file mode 100644 index 7211a0348f..0000000000 --- a/apps/func-migration-v3-import/src/index.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { app, InvocationContext, StorageBlobHandler } from '@azure/functions' -import { closeLegacyConnection } from './getLegacyResults' -import { importQuestionInstances } from './importQuestionInstances' -import { importQuestions } from './importQuestions' -import { importSessions } from './importSessions' -import { importTags } from './importTags' -import { migrateFiles } from './migrateFiles' -import getPrismaClient from './prisma' -import { sendEmailMigrationNotification, sendTeamsNotifications } from './utils' - -const prisma = getPrismaClient() - -const blobTrigger: StorageBlobHandler = async function ( - blob: unknown, - context: InvocationContext -) { - let email = '' - try { - const data = blob as Buffer - - const content = data.toString() - - context.log(context.triggerMetadata?.blobTrigger) - - const newUserId = ( - context.triggerMetadata?.blobTrigger - ? (context.triggerMetadata?.blobTrigger as string) - : undefined - ) - .split('/') - [process.env.NODE_ENV === 'development' ? 1 : 2].split('_')[0] - - const parsedContent = JSON.parse(content) - - context.log( - `MigrationV3Import function processing a new exported blob with originalEmail: ${parsedContent['user_email']} and new user id: ${newUserId}` - ) - - const user = await prisma.user.findUnique({ - where: { - id: newUserId, - }, - }) - - if (!user) { - throw new Error('User not found') - } - - email = user.email - - await sendTeamsNotifications( - 'func/migration-v3-import', - `Started import of KlickerV2 data for user '${user.email}'`, - context - ) - - // keep information in memory for more efficient lookup - let mappedTags: Record> = {} - let mappedFileURLs: Record> = {} - let mappedQuestionIds: Record = {} - let mappedQuestionInstancesIds: Record = {} - let mappedSessionIds: Record = {} - - mappedFileURLs = await migrateFiles( - prisma, - parsedContent.files, - context, - user - ) - - // context.log('mappedFileURLs: ', mappedFileURLs) - - const batchSize = 10 - - const tags = parsedContent.tags - mappedTags = await importTags(prisma, tags, user, batchSize, context) - // context.log('mappedTags: ', mappedTags) - - const questions = parsedContent.questions - mappedQuestionIds = await importQuestions( - prisma, - questions, - mappedTags, - user, - batchSize, - mappedFileURLs, - context - ) - // context.log('mappedQuestionIds: ', mappedQuestionIds) - - const questionInstances = parsedContent.questioninstances - mappedQuestionInstancesIds = await importQuestionInstances( - prisma, - questionInstances, - mappedQuestionIds, - user, - batchSize, - context - ) - // context.log('mappedQuestionInstancesIds: ', mappedQuestionInstancesIds) - - const sessions = parsedContent.sessions - mappedSessionIds = await importSessions( - prisma, - sessions, - mappedQuestionInstancesIds, - user, - batchSize, - context - ) - // context.log('mappedSessionIds: ', mappedSessionIds) - - await sendTeamsNotifications( - 'func/migration-v3-import', - `Successful import for user '${user.email}'`, - context - ) - await sendEmailMigrationNotification(user.email, true, context) - } catch (e) { - context.error('Something went wrong while importing data: ', e) - await sendTeamsNotifications( - 'func/migration-v3-import', - `Import of KlickerV2 data failed. Error: ${e.message}`, - context - ) - await sendEmailMigrationNotification(email, false, context) - throw new Error('Something went wrong while importing data') - } finally { - await closeLegacyConnection() - await prisma.$disconnect() - } -} - -export default blobTrigger - -app.storageBlob('MigrationV3Import', { - connection: 'MIGRATION_BLOB_IMPORT_CONNECTION_STRING', - path: 'exports', - handler: blobTrigger, -}) diff --git a/apps/func-migration-v3-import/src/migrateFiles.ts b/apps/func-migration-v3-import/src/migrateFiles.ts deleted file mode 100644 index 55c7564302..0000000000 --- a/apps/func-migration-v3-import/src/migrateFiles.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { InvocationContext } from '@azure/functions' -import { PrismaClient, User } from '@klicker-uzh/prisma' -import axios from 'axios' -import { v5 as uuidv5 } from 'uuid' -import getBlobClient from './blob' -import { sendTeamsNotifications } from './utils' - -export const migrateFiles = async ( - prisma: PrismaClient, - files: any, - context: InvocationContext, - user: User -) => { - try { - let mappedFileURLs: Record> = {} - const blobClient = await getBlobClient(context, user.id) - - for (const file of files) { - // download file with public link - const response = await axios.get( - `https://tc-klicker-prod.s3.amazonaws.com/images/${file.name}`, - { responseType: 'arraybuffer' } - ) - - // upload file to azure blob storage - const id = uuidv5(file.name, '3cbe686d-2d38-4494-9de2-28046b6241c4') - const extension = file.originalName.split('.').pop() - const blockBlobClient = blobClient.getBlockBlobClient( - `${id}.${extension}` - ) - - // TODO: think about more efficient promise.allSettled or transaction - try { - await prisma.mediaFile.create({ - data: { - id, - name: file.originalName, - type: 'migrated', - href: blockBlobClient.url.split('?')[0], - originalId: file._id, - owner: { - connect: { - id: user.id, - }, - }, - }, - }) - - context.log( - `Uploading file ${file.originalName} to ${blockBlobClient.url}` - ) - - await blockBlobClient.uploadData(response.data, { - blockSize: 4 * 1024 * 1024, // 4MB block size - }) - } catch (e) { - // TODO: catch duplicate file - if (!e.message.includes('Unique constraint failed')) { - throw e - } - } - - const publicUrl = blockBlobClient.url.split('?')[0] - mappedFileURLs[file._id] = { - id, - url: publicUrl, - originalName: file.originalName, - } - } - - return mappedFileURLs - } catch (error) { - context.error('Something went wrong while migrating files: ', error) - await sendTeamsNotifications( - 'func/migration-v3-import', - `Failed migration of images for user '${user.email}'`, - context - ) - throw error - } -} diff --git a/apps/func-migration-v3-import/src/prisma.ts b/apps/func-migration-v3-import/src/prisma.ts deleted file mode 100644 index 459b96f042..0000000000 --- a/apps/func-migration-v3-import/src/prisma.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { InvocationContext } from '@azure/functions' -import { PrismaClient } from '@klicker-uzh/prisma' - -let prisma: PrismaClient - -function getPrismaClient(context?: InvocationContext) { - if (!prisma) { - try { - prisma = new PrismaClient() - } catch (e) { - context?.error(e) - } - } - - return prisma -} - -export default getPrismaClient diff --git a/apps/func-migration-v3-import/src/utils.ts b/apps/func-migration-v3-import/src/utils.ts deleted file mode 100644 index 941ec1ce45..0000000000 --- a/apps/func-migration-v3-import/src/utils.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { InvocationContext } from '@azure/functions' -import { ElementType } from '@klicker-uzh/prisma' -import axios from 'axios' - -export function sliceIntoChunks(array: any[], chunkSize: number) { - const result = [] - let index = 0 - while (index < array.length) { - result.push(array.slice(index, index + chunkSize)) - index += chunkSize - } - return result -} - -export const QuestionTypeMap: Record = { - SC: 'SC', - MC: 'MC', - FREE_RANGE: 'NUMERICAL', - FREE: 'FREE_TEXT', -} - -export async function sendTeamsNotifications( - scope: string, - text: string, - context: InvocationContext -) { - if (process.env.TEAMS_WEBHOOK_URL) { - try { - return axios.post(process.env.TEAMS_WEBHOOK_URL, { - '@context': 'https://schema.org/extensions', - '@type': 'MessageCard', - themeColor: '0076D7', - title: `Migration: ${scope}`, - text: `[${process.env.NODE_ENV}:${scope}] ${text}`, - }) - } catch (e) { - context.error(e) - } - } - - return null -} - -export async function sendEmailMigrationNotification( - email: string, - success: boolean, - context: InvocationContext -) { - const LISTMONK_AUTH = { - username: process.env.LISTMONK_USER as string, - password: process.env.LISTMONK_PASS as string, - } - - try { - // add the user as a subscriber to enable sending emails via listmonk - await axios.post( - `${process.env.LISTMONK_URL}/api/subscribers`, - { - email: email, - name: email, - status: 'enabled', - preconfirm_subscriptions: true, - }, - { auth: LISTMONK_AUTH } - ) - } catch (e: any) { - context.error(e) - // if (e.response.status !== 409) { - // context.error(e) - // } - } - - try { - const result = axios.post( - `${process.env.LISTMONK_URL}/api/tx`, - { - subscriber_emails: [email], - template_id: success - ? Number(process.env.LISTMONK_TEMPLATE_MIGRATION_SUCCESS) - : Number(process.env.LISTMONK_TEMPLATE_MIGRATION_FAILED), - }, - { auth: LISTMONK_AUTH } - ) - - context.log(result) - - return result - } catch (e) { - context.error(e) - } - - return null -} diff --git a/apps/func-migration-v3-import/tsconfig.json b/apps/func-migration-v3-import/tsconfig.json deleted file mode 100644 index e7462b19eb..0000000000 --- a/apps/func-migration-v3-import/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es6", - "outDir": "dist", - "rootDir": ".", - "sourceMap": true, - "strict": false, - "skipLibCheck": true - } -} diff --git a/apps/func-migration-v3-import/tsup.config.ts b/apps/func-migration-v3-import/tsup.config.ts deleted file mode 100644 index 6a974541d6..0000000000 --- a/apps/func-migration-v3-import/tsup.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { defineConfig } from 'tsup' - -export default defineConfig({ - entry: ['src/index.ts'], - noExternal: [/@klicker-uzh.*/], -}) diff --git a/apps/func-response-processor/package.json b/apps/func-response-processor/package.json index a8400f1107..0607a7e09d 100644 --- a/apps/func-response-processor/package.json +++ b/apps/func-response-processor/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@klicker-uzh/func-response-processor", - "version": "3.3.0-alpha.4", + "version": "3.3.0-alpha.7", "license": "AGPL-3.0", "main": "dist/index.js", "files": [ diff --git a/apps/lti/package.json b/apps/lti/package.json index 7c31e92c95..c39491461d 100644 --- a/apps/lti/package.json +++ b/apps/lti/package.json @@ -32,7 +32,6 @@ "dev:doppler": "doppler run --config dev -- pnpm run dev:lti", "dev:lti": "npm-run-all --parallel dev:build dev:run", "dev:run": "nodemon -w dist/ --exec 'node ./dist/index.js'", - "dev:test": "cross-env NODE_ENV=test pnpm run dev", "start": "node dist/index.js" }, "engines": { diff --git a/apps/office-addin/package.json b/apps/office-addin/package.json index 25e6ec9061..727b9f7344 100644 --- a/apps/office-addin/package.json +++ b/apps/office-addin/package.json @@ -1,6 +1,6 @@ { "name": "@klicker-uzh/office-addin", - "version": "3.3.0-alpha.4", + "version": "3.3.0-alpha.7", "license": "AGPL-3.0", "dependencies": { "@uzh-bf/design-system": "3.0.0-alpha.32", diff --git a/cypress/cypress.config.ts b/cypress/cypress.config.ts index 727bb10d33..a10b5cd669 100644 --- a/cypress/cypress.config.ts +++ b/cypress/cypress.config.ts @@ -1,6 +1,8 @@ import { defineConfig } from 'cypress' export default defineConfig({ + // TODO: no watch mode in CI + watchForFileChanges: true, projectId: 'y436dx', env: { URL_STUDENT: 'http://127.0.0.1:3001/login', diff --git a/cypress/package.json b/cypress/package.json index 008317ecf5..14982a0714 100644 --- a/cypress/package.json +++ b/cypress/package.json @@ -14,7 +14,8 @@ }, "scripts": { "test": "cypress open", - "test:run": "cypress run" + "test:run": "cypress run", + "test:watch": "cypress open --watch" }, "engines": { "node": "=20" diff --git a/deploy/azure/.gitignore b/deploy/azure/.gitignore deleted file mode 100644 index c6958891dd..0000000000 --- a/deploy/azure/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/bin/ -/node_modules/ diff --git a/deploy/azure/Pulumi.prod.yaml b/deploy/azure/Pulumi.prod.yaml deleted file mode 100644 index 0fc4df85af..0000000000 --- a/deploy/azure/Pulumi.prod.yaml +++ /dev/null @@ -1,6 +0,0 @@ -config: - azure-native:location: westeurope - klicker-uzh:sshPublicKey: - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDNYzGwAvSSmpInDGUQJSol+80zgVGKSW4AT1SxF6k/Sm1z746cMyQVH30OSMfgbKWvydrDvZu0vwDbE3blwvBgHWROookWPTwusqAA4TuvSIYsa1XeRv0blno4DQXATgKH8RCeVt8ZrDQc4Fvlrxg3tlhjdsZaUTC4zVSeqTSo+hIXFFxr/kra2aSLbWm8FxGQnQpjBNRTNv2I6HDDiMJ7CD4zBnVRXhrxXyzN9fKjhn/aQ+moS3WAryTY1KJ2Qu1zhyYlFQlWpGArmhmqXmdAj4ElDCBleKmrtA2Y+cP+6+W6pHGCHRD0gbG7dMmVEGhUPwH08CtUEumh+yrRFCnBsGp15yDNQBSInrRsAi0QocDhaCs4Yu1KuYggKpSyl8ux8ZlFV3htqqxZ95K4eSo6xr7cNoZIOz8XPGII/aIH8FMq9Tnn1EsECWyWqShiXdlk3p7CDptPGC9nrPqsRlnIve1eliGO5ATCL8tGWcjxFjy/Z+GDNR9No1qdSct+Gb8cHhTdBvuuvsuQMGzRv5rrkk+iWoqt34FGpWorLiTRpJ0BeAeR8a+cipBgelBjvH7+qAgvH9zOgckBArqXA6VfO/q4f1nCOF/+7k/aWlWg2nX/BBN7wND76JtuMmxp41noJ4PaMuuaMxDxICBaQmRpZchjx5gFLbwGnXN4MqHsxw== - roland.schlaefli@bf.uzh.ch\n - klicker-uzh:sshUser: superuser diff --git a/deploy/azure/Pulumi.yaml b/deploy/azure/Pulumi.yaml deleted file mode 100644 index 052a26af19..0000000000 --- a/deploy/azure/Pulumi.yaml +++ /dev/null @@ -1,3 +0,0 @@ -name: klicker-uzh -runtime: nodejs -description: Infrastructure for hosting the KlickerUZH on MS Azure diff --git a/deploy/azure/_deploy.sh b/deploy/azure/_deploy.sh deleted file mode 100755 index 7b806c84a4..0000000000 --- a/deploy/azure/_deploy.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -doppler run --config prd -- pulumi $1 diff --git a/deploy/azure/doppler.yaml b/deploy/azure/doppler.yaml deleted file mode 100644 index cf45f2e9ab..0000000000 --- a/deploy/azure/doppler.yaml +++ /dev/null @@ -1,3 +0,0 @@ -setup: - project: app - config: prd diff --git a/deploy/azure/index.ts b/deploy/azure/index.ts deleted file mode 100644 index 730f5b0364..0000000000 --- a/deploy/azure/index.ts +++ /dev/null @@ -1,528 +0,0 @@ -import * as azure from '@pulumi/azure-native' -import * as k8s from '@pulumi/kubernetes' -import * as pulumi from '@pulumi/pulumi' - -const cfg = new pulumi.Config() - -const PREFIX = 'klicker' -const LOCATION = 'westeurope' - -const VERSION_INGRESS = '4.0.17' -const VERSION_CERT_MANAGER = '1.7.1' - -const RG_MAIN = process.env['RESOURCE_GROUP_MAIN'] as string -const RG_AUX = process.env['RESOURCE_GROUP_AUX'] as string -const SUBNET_IBF = process.env['SUBNET_IBF'] as string -const SUBNET_UZH = process.env['SUBNET_UZH'] as string -const CERT_EMAIL = process.env['CERT_EMAIL'] as string - -if (!CERT_EMAIL) process.exit(0) - -const INGRESS_RECORDS = [ - { - name: `${PREFIX}-wildcard-dns`, - relativeRecordSetName: `*.klicker`, - }, - // { - // name: `${PREFIX}-prod`, - // relativeRecordSetName: '*.klicker-prod', - // }, - // { - // name: `${PREFIX}-faculties`, - // relativeRecordSetName: '*.klicker-faculties', - // }, - { - name: `${PREFIX}-qa`, - relativeRecordSetName: '*.klicker-qa', - }, -] - -const mainRG = new azure.resources.ResourceGroup( - `${PREFIX}-rg`, - { - location: 'switzerlandnorth', - resourceGroupName: RG_MAIN, - tags: { - 'Org-Unit': 'IBF', - }, - }, - { - protect: true, - } -) - -const auxiliaryRG = new azure.resources.ResourceGroup( - `devops-rg`, - { - location: 'switzerlandnorth', - resourceGroupName: RG_AUX, - tags: { - 'Org-Unit': 'IBF', - }, - }, - { - protect: true, - } -) - -// link to the bf-app.ch domain to work with DNS resources -const dnsZone = new azure.network.Zone( - 'bf-app', - { - location: 'global', - resourceGroupName: auxiliaryRG.name, - zoneName: 'bf-app.ch', - zoneType: 'Public', - }, - { - protect: true, - } -) - -// ----- BOOTSTRAP AZURE RESOURCES ----- - -// create a new vnet that will be used for all internal communications -const vnet = new azure.network.VirtualNetwork( - `${PREFIX}-vnet`, - { - location: LOCATION, - resourceGroupName: mainRG.name, - addressSpace: { - addressPrefixes: ['10.8.0.0/16'], - }, - enableDdosProtection: false, - }, - { - ignoreChanges: ['subnets'], - protect: true, - } -) - -// create a default subnet for all internal communication -const defaultSubnet = new azure.network.Subnet( - `${PREFIX}-subnet-default`, - { - resourceGroupName: mainRG.name, - virtualNetworkName: vnet.name, - // the default subnet consists of 4,094 usable hosts - // more specifically, 10.8.0.1 - 10.8.15.254 - addressPrefix: '10.8.0.0/20', - serviceEndpoints: [ - { - locations: ['*'], - service: 'Microsoft.AzureCosmosDB', - }, - ], - }, - { - protect: true, - } -) - -// create a log analytics workspace for kubernetes monitoring -const logAnalytics = new azure.operationalinsights.Workspace( - `${PREFIX}-logging`, - { - resourceGroupName: mainRG.name, - location: LOCATION, - sku: { - name: azure.operationalinsights.WorkspaceSkuNameEnum.PerGB2018, - }, - retentionInDays: 30, - workspaceCapping: { - dailyQuotaGb: 0.4, - }, - } -) - -const klickerProdCosmosDB = new azure.documentdb.DatabaseAccount( - `${PREFIX}-cosmosdb`, - { - apiProperties: { - serverVersion: azure.documentdb.ServerVersion.ServerVersion_4_0, - }, - backupPolicy: { - type: 'Continuous', - }, - capabilities: [ - { - name: 'EnableMongo', - }, - { - name: 'DisableRateLimitingResponses', - }, - { - name: 'EnableServerless', - }, - ], - consistencyPolicy: { - defaultConsistencyLevel: 'Session', - }, - databaseAccountOfferType: 'Standard', - defaultIdentity: 'FirstPartyIdentity', - disableKeyBasedMetadataWriteAccess: false, - enableAnalyticalStorage: false, - enableAutomaticFailover: false, - enableFreeTier: false, - enableMultipleWriteLocations: false, - isVirtualNetworkFilterEnabled: true, - identity: { - type: 'None', - }, - ipRules: [ - { - ipAddressOrRange: '51.138.0.0/16', - }, - { - ipAddressOrRange: '51.124.0.0/16', - }, - { - ipAddressOrRange: '20.50.2.42', - }, - { - ipAddressOrRange: '40.114.174.73', - }, - { - ipAddressOrRange: '20.126.0.0/16', - }, - { - ipAddressOrRange: '20.31.0.0/16', - }, - { - ipAddressOrRange: '20.105.0.0/16', - }, - ], - kind: 'MongoDB', - location: LOCATION, - locations: [ - { - failoverPriority: 0, - isZoneRedundant: false, - locationName: LOCATION, - }, - ], - networkAclBypass: 'None', - publicNetworkAccess: 'Enabled', - resourceGroupName: mainRG.name, - tags: { - defaultExperience: 'Azure Cosmos DB for MongoDB API', - 'hidden-cosmos-mmspecial': '', - }, - virtualNetworkRules: [ - { - id: defaultSubnet.id, - ignoreMissingVNetServiceEndpoint: false, - }, - ], - }, - { - protect: true, - } -) - -// create a kubernetes cluster for workloads -const k8sCluster = new azure.containerservice.ManagedCluster( - `${PREFIX}-k8s`, - { - addonProfiles: { - aciConnectorLinux: { - enabled: false, - }, - // enable the azure policy addon to ensure compliance can be verified - azurepolicy: { - enabled: true, - }, - httpApplicationRouting: { - enabled: false, - }, - // enable the container monitoring plugin to allow azure monitor to integrate with running containers - omsagent: { - enabled: true, - config: { - logAnalyticsWorkspaceResourceId: logAnalytics.id, - }, - }, - }, - agentPoolProfiles: [ - { - availabilityZones: ['1', '2', '3'], - count: 3, - enableAutoScaling: true, - maxCount: 2, - minCount: 1, - enableFIPS: false, - enableNodePublicIP: false, - kubeletDiskType: 'OS', - maxPods: 110, - mode: 'User', - name: 'apps', - osDiskType: 'Ephemeral', - osDiskSizeGB: 30, - osType: 'Linux', - orchestratorVersion: '1.22.4', - osSKU: 'Ubuntu', - type: 'VirtualMachineScaleSets', - vmSize: 'Standard_D2as_v4', - vnetSubnetID: defaultSubnet.id, - }, - { - availabilityZones: ['1', '2', '3'], - count: 0, - minCount: 0, - maxCount: 1, - enableAutoScaling: true, - enableFIPS: false, - enableNodePublicIP: false, - kubeletDiskType: 'OS', - maxPods: 110, - mode: 'User', - name: 'compute', - osDiskType: 'Ephemeral', - osDiskSizeGB: 30, - osType: 'Linux', - orchestratorVersion: '1.22.4', - osSKU: 'Ubuntu', - type: 'VirtualMachineScaleSets', - vmSize: 'Standard_F4s_v2', - vnetSubnetID: defaultSubnet.id, - // add taints to all compute nodes to ensure that nothing is scheduled there - // except workloads that explicitly tolerate the taint - nodeTaints: ['key=compute:NoSchedule'], - }, - { - availabilityZones: ['1', '2', '3'], - count: 1, - enableAutoScaling: false, - enableFIPS: false, - enableNodePublicIP: false, - kubeletDiskType: 'OS', - maxPods: 110, - mode: 'System', - name: 'system', - osDiskType: 'Ephemeral', - osDiskSizeGB: 30, - osType: 'Linux', - orchestratorVersion: '1.22.4', - osSKU: 'Ubuntu', - type: 'VirtualMachineScaleSets', - vmSize: 'Standard_D2as_v4', - vnetSubnetID: defaultSubnet.id, - }, - ], - apiServerAccessProfile: { - enablePrivateCluster: false, - authorizedIPRanges: [SUBNET_IBF, SUBNET_UZH], - }, - identity: { - type: 'SystemAssigned', - }, - dnsPrefix: `${PREFIX}-k8s-dns`, - enableRBAC: true, - kubernetesVersion: '1.22.4', - location: LOCATION, - networkProfile: { - loadBalancerSku: 'Standard', - networkPlugin: 'azure', - networkPolicy: 'azure', - outboundType: 'loadBalancer', - }, - resourceGroupName: mainRG.name, - servicePrincipalProfile: { - clientId: 'msi', - }, - sku: { - name: 'Basic', - tier: 'Free', - }, - }, - { - protect: true, - } -) - -const k8sCredentials = pulumi - .all([mainRG.name, k8sCluster.name]) - .apply((args) => - azure.containerservice.listManagedClusterAdminCredentials({ - resourceGroupName: args[0], - resourceName: args[1], - }) - ) - -const kubeConfig = k8sCredentials.kubeconfigs[0].value.apply((enc) => - Buffer.from(enc, 'base64').toString('utf-8') -) - -// ----- BOOTSTRAP KUBERNETES CLUSTER ----- - -// get access to the kubeconfig of the previously created cluster -// crucial to include this in all subsequent operations, otherwise it will use the currently activated kubectl context -const k8sProvider = new k8s.Provider(`${PREFIX}-k8s-provider`, { - kubeconfig: kubeConfig, -}) - -// deploy ingress-nginx -const ingressNginx = new k8s.helm.v3.Release( - `${PREFIX}-ingress-nginx`, - { - chart: 'ingress-nginx', - version: VERSION_INGRESS, - namespace: 'ingress-nginx', - createNamespace: true, - repositoryOpts: { - repo: 'https://kubernetes.github.io/ingress-nginx', - }, - values: { - controller: { - replicaCount: 2, - service: { - externalTrafficPolicy: 'Local', - }, - nodeSelector: { - 'beta.kubernetes.io/os': 'linux', - }, - admissionWebhooks: { - patch: { - nodeSelector: { - 'beta.kubernetes.io/os': 'linux', - }, - }, - }, - watchIngressWithoutClass: true, - }, - defaultBackend: { - nodeSelector: { - 'beta.kubernetes.io/os': 'linux', - }, - }, - }, - }, - { - provider: k8sProvider, - } -) - -// get a handle to the ingress controller to fetch the external ip -const ingressController = k8s.core.v1.Service.get( - `${PREFIX}-ingress-controller`, - pulumi.interpolate`${ingressNginx.status.namespace}/${ingressNginx.status.name}-controller`, - { - provider: k8sProvider, - } -) - -// deploy cert-manager -const certManager = new k8s.helm.v3.Release( - `${PREFIX}-cert-manager`, - { - chart: 'cert-manager', - version: VERSION_CERT_MANAGER, - namespace: 'ingress-nginx', - repositoryOpts: { - repo: 'https://charts.jetstack.io', - }, - values: { - installCRDs: true, - nodeSelector: { - 'kubernetes.io/os': 'linux', - }, - webhook: { - nodeSelector: { - 'kubernetes.io/os': 'linux', - }, - }, - cainjector: { - nodeSelector: { - 'kubernetes.io/os': 'linux', - }, - }, - }, - }, - { - provider: k8sProvider, - dependsOn: [ingressNginx], - } -) - -const lbRecordSet = new azure.network.RecordSet(`${PREFIX}-lb-dns`, { - resourceGroupName: auxiliaryRG.name, - zoneName: dnsZone.name, - recordType: 'A', - relativeRecordSetName: 'klicker', - ttl: 360, - aRecords: [ - { - ipv4Address: ingressController.status.loadBalancer.ingress[0].ip, - }, - ], -}) - -const ingressRecordSets = INGRESS_RECORDS.map( - ({ name, relativeRecordSetName }) => - new azure.network.RecordSet(name, { - resourceGroupName: auxiliaryRG.name, - zoneName: dnsZone.name, - recordType: 'A', - relativeRecordSetName, - ttl: 360, - targetResource: { - id: lbRecordSet.id, - }, - }) -) - -// deploy the clusterissuer for letsencrypt -const certManagerIssuer = new k8s.yaml.ConfigGroup( - `${PREFIX}-cert-manager-issuer`, - { - yaml: ` - apiVersion: cert-manager.io/v1 - kind: ClusterIssuer - metadata: - name: letsencrypt - spec: - acme: - server: https://acme-v02.api.letsencrypt.org/directory - email: ${CERT_EMAIL} - privateKeySecretRef: - name: letsencrypt - solvers: - - http01: - ingress: - class: nginx - podTemplate: - spec: - nodeSelector: - 'kubernetes.io/os': linux - `, - }, - { - provider: k8sProvider, - dependsOn: [certManager], - } -) - -// deploy the a storageclass for ZRS -const storageClassZRS = new k8s.yaml.ConfigGroup( - `${PREFIX}-storage-zrs`, - { - yaml: ` -kind: StorageClass -apiVersion: storage.k8s.io/v1 -metadata: - name: default-zrs - labels: - addonmanager.kubernetes.io/mode: EnsureExists - kubernetes.io/cluster-service: 'true' -provisioner: disk.csi.azure.com -parameters: - skuname: StandardSSD_ZRS -reclaimPolicy: Delete -allowVolumeExpansion: true -volumeBindingMode: WaitForFirstConsumer - `, - }, - { - provider: k8sProvider, - } -) diff --git a/deploy/azure/package-lock.json b/deploy/azure/package-lock.json deleted file mode 100644 index e50c87ebe1..0000000000 --- a/deploy/azure/package-lock.json +++ /dev/null @@ -1,2119 +0,0 @@ -{ - "name": "klicker-uzh", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "klicker-uzh", - "dependencies": { - "@pulumi/azure-native": "^1.0.0", - "@pulumi/kubernetes": "3.16.0", - "@pulumi/pulumi": "^3.0.0" - }, - "devDependencies": { - "@types/node": "^14" - } - }, - "node_modules/@grpc/grpc-js": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.3.8.tgz", - "integrity": "sha512-4qJqqn+CU/nBydz9ePJP+oa8dz0U42Ut/GejlbyaQ1xTkynCc+ndNHHnISlNeHawDsv4MOAyP3mV/EnDNUw2zA==", - "dependencies": { - "@types/node": ">=12.12.47" - }, - "engines": { - "node": "^8.13.0 || >=10.10.0" - } - }, - "node_modules/@logdna/tail-file": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@logdna/tail-file/-/tail-file-2.1.0.tgz", - "integrity": "sha512-8zYzetB1zfa7WA4c0RS1EU9pNKcj1BqilU2fCsEvmKfWgEdpaphff6hk2Rcn3A0qHwynEdw9lTrlYN4sUw2FpA==", - "engines": { - "node": ">=10.3.0" - } - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" - }, - "node_modules/@pulumi/azure-native": { - "version": "1.58.0", - "resolved": "https://registry.npmjs.org/@pulumi/azure-native/-/azure-native-1.58.0.tgz", - "integrity": "sha512-Zk9SpeA8o0eC7xvzkGMDIvXz+ef9Ky28D/4Y5Tas0tYU5tITZLPU68iiCzbRAYiRJrBqXz6ng4dZGDnPiP9xQQ==", - "hasInstallScript": true, - "dependencies": { - "@pulumi/pulumi": "^3.0.0" - } - }, - "node_modules/@pulumi/kubernetes": { - "version": "3.16.0", - "resolved": "https://registry.npmjs.org/@pulumi/kubernetes/-/kubernetes-3.16.0.tgz", - "integrity": "sha512-nQef0OXTgWIdPOsQQWHWlKPzj26TpHdU9gqgJXhaBvkQUj7jiD/S8w+4jNDFof7ykPZ3I0bd1ycQYVz/lCMVkQ==", - "hasInstallScript": true, - "dependencies": { - "@pulumi/pulumi": "^3.0.0", - "@types/glob": "^5.0.35", - "@types/node-fetch": "^2.1.4", - "@types/tmp": "^0.0.33", - "glob": "^7.1.2", - "node-fetch": "^2.3.0", - "shell-quote": "^1.6.1", - "tmp": "^0.0.33" - } - }, - "node_modules/@pulumi/pulumi": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/@pulumi/pulumi/-/pulumi-3.24.1.tgz", - "integrity": "sha512-tRbf4JgaLnUeImQ3Hco76YJSalp6YNY3CcV//u309iequ7Zyiap/A/acKXkJ3BeDjN7aCJ2wUYNWBjet2zArZA==", - "dependencies": { - "@grpc/grpc-js": "~1.3.8", - "@logdna/tail-file": "^2.0.6", - "@pulumi/query": "^0.3.0", - "google-protobuf": "^3.5.0", - "js-yaml": "^3.14.0", - "minimist": "^1.2.0", - "normalize-package-data": "^2.4.0", - "protobufjs": "^6.8.6", - "read-package-tree": "^5.3.1", - "require-from-string": "^2.0.1", - "semver": "^6.1.0", - "source-map-support": "^0.4.16", - "ts-node": "^7.0.1", - "typescript": "~3.7.3", - "upath": "^1.1.0" - }, - "engines": { - "node": ">=8.13.0 || >=10.10.0" - } - }, - "node_modules/@pulumi/query": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@pulumi/query/-/query-0.3.0.tgz", - "integrity": "sha512-xfo+yLRM2zVjVEA4p23IjQWzyWl1ZhWOGobsBqRpIarzLvwNH/RAGaoehdxlhx4X92302DrpdIFgTICMN4P38w==" - }, - "node_modules/@types/glob": { - "version": "5.0.37", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-5.0.37.tgz", - "integrity": "sha512-ATA/xrS7CZ3A2WCPVY4eKdNpybq56zqlTirnHhhyOztZM/lPxJzusOBI3BsaXbu6FrUluqzvMlI4sZ6BDYMlMg==", - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "node_modules/@types/long": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", - "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" - }, - "node_modules/@types/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==" - }, - "node_modules/@types/node": { - "version": "14.18.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz", - "integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==" - }, - "node_modules/@types/node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA==", - "dependencies": { - "@types/node": "*", - "form-data": "^3.0.0" - } - }, - "node_modules/@types/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha1-EHPEvIJHVK49EM+riKsCN7qWTk0=" - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "node_modules/debuglog": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=", - "engines": { - "node": "*" - } - }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/dezalgo": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", - "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", - "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "node_modules/diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/google-protobuf": { - "version": "3.19.4", - "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.19.4.tgz", - "integrity": "sha512-OIPNCxsG2lkIvf+P5FNfJ/Km95CsXOBecS9ZcAU6m2Rq3svc0Apl9nB3GMDNKfQ9asNv4KjyAqGwPQFrVle3Yg==" - }, - "node_modules/graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - }, - "node_modules/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" - }, - "node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", - "dependencies": { - "mime-db": "1.51.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" - }, - "node_modules/object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.getownpropertydescriptors": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz", - "integrity": "sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/protobufjs": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", - "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", - "hasInstallScript": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.1", - "@types/node": ">=13.7.0", - "long": "^4.0.0" - }, - "bin": { - "pbjs": "bin/pbjs", - "pbts": "bin/pbts" - } - }, - "node_modules/read-package-json": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", - "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", - "dependencies": { - "glob": "^7.1.1", - "json-parse-even-better-errors": "^2.3.0", - "normalize-package-data": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0" - } - }, - "node_modules/read-package-tree": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz", - "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", - "deprecated": "The functionality that this package provided is now in @npmcli/arborist", - "dependencies": { - "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0", - "util-promisify": "^2.1.0" - } - }, - "node_modules/readdir-scoped-modules": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", - "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", - "dependencies": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "dependencies": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==" - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dependencies": { - "source-map": "^0.5.6" - } - }, - "node_modules/spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", - "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==" - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "node_modules/ts-node": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", - "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", - "dependencies": { - "arrify": "^1.0.0", - "buffer-from": "^1.1.0", - "diff": "^3.1.0", - "make-error": "^1.1.1", - "minimist": "^1.2.0", - "mkdirp": "^0.5.1", - "source-map-support": "^0.5.6", - "yn": "^2.0.0" - }, - "bin": { - "ts-node": "dist/bin.js" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/ts-node/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ts-node/node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/typescript": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.7.tgz", - "integrity": "sha512-MmQdgo/XenfZPvVLtKZOq9jQQvzaUAUpcKW8Z43x9B2fOm4S5g//tPtMweZUIP+SoBqrVPEIm+dJeQ9dfO0QdA==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "engines": { - "node": ">=4", - "yarn": "*" - } - }, - "node_modules/util-promisify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz", - "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=", - "dependencies": { - "object.getownpropertydescriptors": "^2.0.3" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "node_modules/yn": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", - "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", - "engines": { - "node": ">=4" - } - } - }, - "dependencies": { - "@grpc/grpc-js": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.3.8.tgz", - "integrity": "sha512-4qJqqn+CU/nBydz9ePJP+oa8dz0U42Ut/GejlbyaQ1xTkynCc+ndNHHnISlNeHawDsv4MOAyP3mV/EnDNUw2zA==", - "requires": { - "@types/node": ">=12.12.47" - } - }, - "@logdna/tail-file": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@logdna/tail-file/-/tail-file-2.1.0.tgz", - "integrity": "sha512-8zYzetB1zfa7WA4c0RS1EU9pNKcj1BqilU2fCsEvmKfWgEdpaphff6hk2Rcn3A0qHwynEdw9lTrlYN4sUw2FpA==" - }, - "@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" - }, - "@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" - }, - "@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", - "requires": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" - }, - "@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" - }, - "@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" - }, - "@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" - }, - "@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" - }, - "@pulumi/azure-native": { - "version": "1.58.0", - "resolved": "https://registry.npmjs.org/@pulumi/azure-native/-/azure-native-1.58.0.tgz", - "integrity": "sha512-Zk9SpeA8o0eC7xvzkGMDIvXz+ef9Ky28D/4Y5Tas0tYU5tITZLPU68iiCzbRAYiRJrBqXz6ng4dZGDnPiP9xQQ==", - "requires": { - "@pulumi/pulumi": "^3.0.0" - } - }, - "@pulumi/kubernetes": { - "version": "3.16.0", - "resolved": "https://registry.npmjs.org/@pulumi/kubernetes/-/kubernetes-3.16.0.tgz", - "integrity": "sha512-nQef0OXTgWIdPOsQQWHWlKPzj26TpHdU9gqgJXhaBvkQUj7jiD/S8w+4jNDFof7ykPZ3I0bd1ycQYVz/lCMVkQ==", - "requires": { - "@pulumi/pulumi": "^3.0.0", - "@types/glob": "^5.0.35", - "@types/node-fetch": "^2.1.4", - "@types/tmp": "^0.0.33", - "glob": "^7.1.2", - "node-fetch": "^2.3.0", - "shell-quote": "^1.6.1", - "tmp": "^0.0.33" - } - }, - "@pulumi/pulumi": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/@pulumi/pulumi/-/pulumi-3.24.1.tgz", - "integrity": "sha512-tRbf4JgaLnUeImQ3Hco76YJSalp6YNY3CcV//u309iequ7Zyiap/A/acKXkJ3BeDjN7aCJ2wUYNWBjet2zArZA==", - "requires": { - "@grpc/grpc-js": "~1.3.8", - "@logdna/tail-file": "^2.0.6", - "@pulumi/query": "^0.3.0", - "google-protobuf": "^3.5.0", - "js-yaml": "^3.14.0", - "minimist": "^1.2.0", - "normalize-package-data": "^2.4.0", - "protobufjs": "^6.8.6", - "read-package-tree": "^5.3.1", - "require-from-string": "^2.0.1", - "semver": "^6.1.0", - "source-map-support": "^0.4.16", - "ts-node": "^7.0.1", - "typescript": "~3.7.3", - "upath": "^1.1.0" - } - }, - "@pulumi/query": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@pulumi/query/-/query-0.3.0.tgz", - "integrity": "sha512-xfo+yLRM2zVjVEA4p23IjQWzyWl1ZhWOGobsBqRpIarzLvwNH/RAGaoehdxlhx4X92302DrpdIFgTICMN4P38w==" - }, - "@types/glob": { - "version": "5.0.37", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-5.0.37.tgz", - "integrity": "sha512-ATA/xrS7CZ3A2WCPVY4eKdNpybq56zqlTirnHhhyOztZM/lPxJzusOBI3BsaXbu6FrUluqzvMlI4sZ6BDYMlMg==", - "requires": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/long": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", - "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" - }, - "@types/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==" - }, - "@types/node": { - "version": "14.18.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.12.tgz", - "integrity": "sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A==" - }, - "@types/node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-oMqjURCaxoSIsHSr1E47QHzbmzNR5rK8McHuNb11BOM9cHcIK3Avy0s/b2JlXHoQGTYS3NsvWzV1M0iK7l0wbA==", - "requires": { - "@types/node": "*", - "form-data": "^3.0.0" - } - }, - "@types/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha1-EHPEvIJHVK49EM+riKsCN7qWTk0=" - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" - }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "debuglog": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=" - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "requires": { - "object-keys": "^1.0.12" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "dezalgo": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", - "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", - "requires": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==" - }, - "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" - }, - "form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "google-protobuf": { - "version": "3.19.4", - "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.19.4.tgz", - "integrity": "sha512-OIPNCxsG2lkIvf+P5FNfJ/Km95CsXOBecS9ZcAU6m2Rq3svc0Apl9nB3GMDNKfQ9asNv4KjyAqGwPQFrVle3Yg==" - }, - "graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" - }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "requires": { - "has-symbols": "^1.0.2" - } - }, - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==" - }, - "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==" - }, - "is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==" - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "requires": { - "call-bind": "^1.0.2" - } - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - }, - "long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" - }, - "mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" - }, - "mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", - "requires": { - "mime-db": "1.51.0" - } - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "requires": { - "minimist": "^1.2.5" - } - }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "requires": { - "whatwg-url": "^5.0.0" - } - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" - }, - "object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==" - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" - }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - }, - "object.getownpropertydescriptors": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz", - "integrity": "sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "protobufjs": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.2.tgz", - "integrity": "sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw==", - "requires": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/long": "^4.0.1", - "@types/node": ">=13.7.0", - "long": "^4.0.0" - } - }, - "read-package-json": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", - "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", - "requires": { - "glob": "^7.1.1", - "json-parse-even-better-errors": "^2.3.0", - "normalize-package-data": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0" - } - }, - "read-package-tree": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz", - "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", - "requires": { - "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0", - "util-promisify": "^2.1.0" - } - }, - "readdir-scoped-modules": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", - "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", - "requires": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" - }, - "resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", - "requires": { - "is-core-module": "^2.8.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "shell-quote": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz", - "integrity": "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==" - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - }, - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "requires": { - "source-map": "^0.5.6" - } - }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz", - "integrity": "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==" - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" - }, - "ts-node": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", - "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", - "requires": { - "arrify": "^1.0.0", - "buffer-from": "^1.1.0", - "diff": "^3.1.0", - "make-error": "^1.1.1", - "minimist": "^1.2.0", - "mkdirp": "^0.5.1", - "source-map-support": "^0.5.6", - "yn": "^2.0.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - } - } - }, - "typescript": { - "version": "3.7.7", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.7.tgz", - "integrity": "sha512-MmQdgo/XenfZPvVLtKZOq9jQQvzaUAUpcKW8Z43x9B2fOm4S5g//tPtMweZUIP+SoBqrVPEIm+dJeQ9dfO0QdA==" - }, - "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - } - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" - }, - "util-promisify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz", - "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=", - "requires": { - "object.getownpropertydescriptors": "^2.0.3" - } - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "yn": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", - "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=" - } - } -} diff --git a/deploy/azure/package.json b/deploy/azure/package.json deleted file mode 100644 index 38c081c140..0000000000 --- a/deploy/azure/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "klicker-uzh", - "devDependencies": { - "@types/node": "^14" - }, - "dependencies": { - "@pulumi/azure-native": "^1.0.0", - "@pulumi/kubernetes": "3.16.0", - "@pulumi/pulumi": "^3.0.0" - }, - "volta": { - "node": "16.14.0", - "npm": "8.5.0" - } -} diff --git a/deploy/azure/tsconfig.json b/deploy/azure/tsconfig.json deleted file mode 100644 index 9469ac5676..0000000000 --- a/deploy/azure/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "strict": true, - "outDir": "bin", - "target": "es2016", - "module": "commonjs", - "moduleResolution": "node", - "sourceMap": true, - "experimentalDecorators": true, - "pretty": true, - "noFallthroughCasesInSwitch": true, - "noImplicitReturns": true, - "forceConsistentCasingInFileNames": true - }, - "files": ["index.ts"] -} diff --git a/deploy/charts/klicker-uzh-v2/templates/cm-backend-graphql.yaml b/deploy/charts/klicker-uzh-v2/templates/cm-backend-graphql.yaml index 9015455b74..728ca06972 100644 --- a/deploy/charts/klicker-uzh-v2/templates/cm-backend-graphql.yaml +++ b/deploy/charts/klicker-uzh-v2/templates/cm-backend-graphql.yaml @@ -20,11 +20,6 @@ data: REDIS_CACHE_HOST: {{ .Values.backendGraphql.redisCache.host | quote }} REDIS_CACHE_PORT: {{ .Values.backendGraphql.redisCache.port | quote }} BLOB_STORAGE_ACCOUNT_NAME: {{ .Values.blobStorage.accountName | quote }} - LISTMONK_URL: {{ .Values.listmonk.url | quote }} - LISTMONK_USER: {{ .Values.listmonk.username | quote }} - LISTMONK_TEMPLATE_MIGRATION_EMAIL_NOT_AVAILABLE: {{ .Values.listmonk.templates.emailNotFound | quote }} - LISTMONK_TEMPLATE_MIGRATION_REQUEST: {{ .Values.listmonk.templates.migrationRequest | quote }} - MIGRATION_SERVICE_BUS_QUEUE_NAME: {{ .Values.migration.serviceBus.queueName | quote }} EMAIL_TYPE: {{ .Values.email.type | quote }} EMAIL_FROM: {{ .Values.email.from | quote }} EMAIL_HOST: {{ .Values.email.host | quote }} diff --git a/deploy/charts/klicker-uzh-v2/templates/secret-backend-graphql.yaml b/deploy/charts/klicker-uzh-v2/templates/secret-backend-graphql.yaml index 32c14bde7f..570ea33b79 100644 --- a/deploy/charts/klicker-uzh-v2/templates/secret-backend-graphql.yaml +++ b/deploy/charts/klicker-uzh-v2/templates/secret-backend-graphql.yaml @@ -15,8 +15,4 @@ stringData: REDIS_CACHE_PASS: {{ .Values.backendGraphql.redisCache.pass | quote }} REDIS_PASS: {{ .Values.backendGraphql.redisExec.pass | quote }} BLOB_STORAGE_ACCESS_KEY: {{ .Values.blobStorage.accessKey | quote }} - MIGRATION_MONGO_CONNECTION_STRING: {{ .Values.migration.mongo.connectionString | quote }} - MIGRATION_SERVICE_BUS_CONNECTION_STRING: {{ .Values.migration.serviceBus.connectionString | quote }} - MIGRATION_SECRET: {{ .Values.migration.secret | quote }} - LISTMONK_PASS: {{ .Values.listmonk.password | quote }} EMAIL_PASS: {{ .Values.email.password | quote }} diff --git a/deploy/charts/klicker-uzh-v2/values.yaml b/deploy/charts/klicker-uzh-v2/values.yaml index 077b19761a..3e8d03e5f8 100644 --- a/deploy/charts/klicker-uzh-v2/values.yaml +++ b/deploy/charts/klicker-uzh-v2/values.yaml @@ -32,22 +32,6 @@ blobStorage: accountName: '' accessKey: '' -migration: - secret: '' - mongo: - connectionString: '' - serviceBus: - connectionString: '' - queueName: '' - -listmonk: - url: '' - username: '' - password: '' - templates: - migrationRequest: -1 - emailNotFound: -1 - vapid: publicKey: '' privateKey: '' diff --git a/deploy/compose-traefik-proxy/klicker/docker-compose.yml b/deploy/compose-traefik-proxy/klicker/docker-compose.yml index 6609011d23..275f06385d 100644 --- a/deploy/compose-traefik-proxy/klicker/docker-compose.yml +++ b/deploy/compose-traefik-proxy/klicker/docker-compose.yml @@ -80,16 +80,6 @@ services: restart: unless-stopped image: redis:5.0.9 - # mongodb database - # it is recommended to run this service outside of docker - mongodb: - restart: unless-stopped - image: mongo:4.0 - env_file: services.env - volumes: - #- /data/klicker/mongo/:/data/db - - mongo-data:/data/db - # minio storage platform for S3 minio: restart: unless-stopped @@ -136,7 +126,6 @@ services: volumes: redis-data: minio-data: - mongo-data: networks: traefik_proxy: diff --git a/deploy/compose-traefik-proxy/klicker/services.env b/deploy/compose-traefik-proxy/klicker/services.env index 431cad39d9..70bf06d1f5 100644 --- a/deploy/compose-traefik-proxy/klicker/services.env +++ b/deploy/compose-traefik-proxy/klicker/services.env @@ -35,16 +35,12 @@ S3_ENDPOINT=https://your-domain.example APP_SECRET=56f79f1625e311ec8a8e2fff30e1c79a -MONGO_PASSWORD=5a900ae625e311eca314cf6a19e3845a - ## internal APP_HTTPS=false CACHE_REDIS_PORT=6379 EXEC_REDIS_HOST=redis_exec EXEC_REDIS_PORT=6379 EXEC_REDIS_TLS=false -MONGO_URL=mongodb:27017/klicker?authSource=admin -MONGO_USER=klicker S3_ENABLED=true S3_ACCESS_KEY=minioadmin S3_BUCKET=images @@ -52,16 +48,6 @@ SECURITY_CORS_CREDENTIALS=true SECURITY_HSTS_ENABLED=false SECURITY_RATE_LIMIT_ENABLED=true - - - -# mongo -MONGO_INITDB_ROOT_USERNAME=klicker -MONGO_INITDB_ROOT_PASSWORD=5a900ae625e311eca314cf6a19e3845a - - - - # minio MINIO_API_CORS_ALLOW_ORIGIN=https://your-domain.example diff --git a/deploy/compose/docker-compose.yml b/deploy/compose/docker-compose.yml index 1da2a8577a..651738c4bd 100644 --- a/deploy/compose/docker-compose.yml +++ b/deploy/compose/docker-compose.yml @@ -56,9 +56,6 @@ services: EMAIL_PORT: EMAIL_USER: EMAIL_PASSWORD: - MONGO_URL: mongodb:27017/klicker?authSource=admin - MONGO_USER: klicker - MONGO_PASSWORD: klicker S3_ENABLED: 'true' S3_ACCESS_KEY: minioadmin S3_SECRET_KEY: minioadmin @@ -94,21 +91,6 @@ services: networks: - klicker - # mongodb database - # it is recommended to run this service outside of docker - mongodb: - restart: unless-stopped - image: mongo:4.0 - environment: - MONGO_INITDB_ROOT_USERNAME: klicker - MONGO_INITDB_ROOT_PASSWORD: klicker - # ports: - # - 27017:27017 - networks: - - klicker - volumes: - - mongo-data:/data/db - # minio storage platform for S3 minio: restart: unless-stopped @@ -144,7 +126,6 @@ services: volumes: redis-data: minio-data: - mongo-data: networks: klicker: diff --git a/deploy/env-prod-v3/helmfile.yaml b/deploy/env-prod-v3/helmfile.yaml index e91ce48bd4..2a2ba925f9 100644 --- a/deploy/env-prod-v3/helmfile.yaml +++ b/deploy/env-prod-v3/helmfile.yaml @@ -32,22 +32,6 @@ releases: accountName: '{{ requiredEnv "BLOB_STORAGE_ACCOUNT_NAME" }}' accessKey: '{{ requiredEnv "BLOB_STORAGE_ACCESS_KEY" }}' - migration: - secret: '{{ requiredEnv "MIGRATION_SECRET" }}' - mongo: - connectionString: '{{ requiredEnv "MIGRATION_MONGO_CONNECTION_STRING" }}' - serviceBus: - connectionString: '{{ requiredEnv "MIGRATION_SERVICE_BUS_CONNECTION_STRING" }}' - queueName: '{{ requiredEnv "MIGRATION_SERVICE_BUS_QUEUE_NAME" }}' - - listmonk: - url: '{{ requiredEnv "LISTMONK_URL" }}' - username: '{{ requiredEnv "LISTMONK_USER" }}' - password: '{{ requiredEnv "LISTMONK_PASS" }}' - templates: - emailNotFound: '{{ requiredEnv "LISTMONK_TEMPLATE_EMAIL_NOT_FOUND" }}' - migrationRequest: '{{ requiredEnv "LISTMONK_TEMPLATE_MIGRATION_REQUEST" }}' - cron: token: '{{ requiredEnv "CRON_TOKEN" }}' diff --git a/docker-compose.yml b/docker-compose.yml index 78214d1bce..b23923457c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -111,10 +111,6 @@ services: REDIS_PORT: 6379 # BLOB_STORAGE_ACCESS_KEY: '' # BLOB_STORAGE_ACCOUNT_NAME: '' - # LISTMONK_TEMPLATE_MIGRATION_REQUEST: '' - # LISTMONK_URL: '' - # LISTMONK_USER: '' - # MIGRATION_SERVICE_BUS_QUEUE_NAME: '' # NOTIFICATION_SECRET: '' # REDIS_CACHE_TLS: 'true' # REDIS_TLS: 'true' @@ -167,57 +163,11 @@ services: networks: - klicker - # service for transactional emails and newsletter campaigns - # uses mailhog to send transactional emails during development - listmonk: - image: docker.io/listmonk/listmonk:latest - ports: - - 9000:9000 - environment: - - TZ=Europe/Zurich - depends_on: - listmonk_db: - condition: service_healthy - volumes: - - ./util/listmonk-config.toml:/listmonk/config.toml - networks: - - klicker - command: [sh, -c, 'yes | ./listmonk --install && ./listmonk'] - - listmonk_db: - image: docker.io/library/postgres:13 - environment: - - POSTGRES_PASSWORD=listmonk - - POSTGRES_USER=listmonk - - POSTGRES_DB=listmonk - volumes: - - listmonk_data:/var/lib/postgresql/data - networks: - - klicker - healthcheck: - test: ['CMD-SHELL', 'pg_isready -U listmonk'] - interval: 10s - timeout: 5s - retries: 6 - - mongodb: - image: mongo:4.0 - environment: - MONGO_INITDB_ROOT_USERNAME: klicker - MONGO_INITDB_ROOT_PASSWORD: klicker - ports: - - 27017:27017 - networks: - - klicker - volumes: - - /data/db - networks: klicker: driver: bridge volumes: - listmonk_data: klicker_data: klicker_lti_data: redis_data: diff --git a/email/Migration Failed.html b/email/Migration Failed.html deleted file mode 100644 index b4cbea7959..0000000000 --- a/email/Migration Failed.html +++ /dev/null @@ -1,1112 +0,0 @@ - - - - - - - - - KlickerUZH - Migration Unsuccessful - - - - - - - - - -
- - - - - -
- - - - -
- - - - - - - -
- - - - - -
- - - - -
-

- KlickerUZH v3.0 Migration Unsuccessful
-

-
-
- - - - - -
- - - - -
-

-
-
- -
- - - - -
- - - - - - - -
- -
- -
-
-
-
- - - - -
- - - - -
- - - - -
- - - - -
-

- Dear user of KlickerUZH, -

-

-
-

-

- The migration of your data to the new - KlickerUZH v3.0 could not be completed. - Please try again after some time (e.g., 1 - hour) and if the issue persists (you get - another of these notifications), please - get in touch with us at - klicker@df.uzh.ch - so that we can help you resolve this - issue.
-

-

-
-

-

- We are terribly sorry for the - inconvenience and hope to welcome you to - our new platform very soon. -

-

-
-

-

- Best regards, -

-

- Team KlickerUZH -

-
-
-
-
- - - - - -
-
- - diff --git a/email/Migration Request.html b/email/Migration Request.html deleted file mode 100644 index 6ff824e4a6..0000000000 --- a/email/Migration Request.html +++ /dev/null @@ -1,1161 +0,0 @@ - - - - - - - - - KlickerUZH - Migration Request - - - - - - - - - -
- - - - - -
- - - - -
- - - - - - - -
- - - - - -
- - - - -
-

- KlickerUZH v3.0 Migration Request
-

-
-
- - - - - -
- - - - -
-

-
-
- -
- - - - -
- - - - - - - -
- -
- -
-
-
-
- - - - -
- - - - -
- - - - -
- - - - -
-

- Dear user of KlickerUZH, -

-

-
-

-

- A migration from KlickerUZH v2.0 to the - new v3.0 has been requested for your - account using this e-mail address. The - migration request has been sent by the new - v3.0 Edu-ID account created using {{ - .Tx.Data.newAccountEmail}}. -

-

-
-

-

- If you would like to proceed with the - migration, please visit the following link - (while logged in to the new KlickerUZH): - START MIGRATION -

-

-
-

-

- Should this migration not have been - requested by you with an Edu-ID using the - e-mail address previously mentioned, - please contact us at - klicker@df.uzh.ch. -

-

-
-

-

- Best regards, -

-

- Team KlickerUZH -

-
-
-
-
- - - - - -
-
- - diff --git a/email/Migration Success.html b/email/Migration Success.html deleted file mode 100644 index a6e68bc750..0000000000 --- a/email/Migration Success.html +++ /dev/null @@ -1,1148 +0,0 @@ - - - - - - - - - KlickerUZH - Migration Successful - - - - - - - - - -
- - - - - -
- - - - -
- - - - - - - -
- - - - - -
- - - - -
-

- KlickerUZH v3.0 Migration Successful -

-
-
- - - - - -
- - - - -
-

-
-
- -
- - - - -
- - - - - - - -
- -
- -
-
-
-
- - - - -
- - - - -
- - - - -
- - - - -
-

- Dear user of KlickerUZH, -

-

-
-

-

- The migration of your data to the new - KlickerUZH v3.0 has been successfully - completed. We are very happy to welcome - you to our new platform and hope you will - find it enjoyable to use. If you have any - feedback, please connect with us through - one of our channels. -

-

-
-

-

- You can repeat the migration at any time - to import new data created within - KlickerUZH v2.0. Please take note that - data that has already been imported will - not be overritten, even if the original - has been changed within KlickerUZH v2.0. -

-

-
-

-

- In case of any issues with the migration, - please connect with us on our community - platform at - https://community.klicker.uzh.ch. -

-

-
-

-

- Best regards, -

-

- Team KlickerUZH -

-
-
-
-
- - - - - -
-
- - diff --git a/package.json b/package.json index 831fe3c696..4cb90a31fc 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "private": true, "name": "@klicker-uzh/monorepo", "description": "KlickerUZH instant-class-response system.", - "version": "3.3.0-alpha.4", + "version": "3.3.0-alpha.7", "repository": "uzh-bf/klicker-uzh.git", "homepage": "https://www.klicker.uzh.ch/", "bugs": "https://github.com/uzh-bf/klicker-uzh/issues", @@ -52,9 +52,8 @@ "dev:cleverreach": "doppler run --config dev_cleverreach -- turbo run dev --concurrency 30", "dev:docs": "turbo run dev:docs", "dev:lti": "doppler run --config dev_lti -- turbo run dev:lti", - "dev:migration": "doppler run --config dev -- turbo run dev:migration", "dev:offline": "doppler run --config dev -- turbo run dev:offline --concurrency 30", - "dev:test": "cross-env NODE_ENV=test turbo run dev:test", + "dev:test": "doppler run --config dev_cypress -- cross-env NODE_ENV=test turbo run dev:test", "format": "prettier --write . --config .prettierrc.mjs", "format:check": "prettier --check . --config .prettierrc.mjs", "lint": "turbo run lint --parallel --continue", @@ -83,7 +82,8 @@ "syncpack:mismatches:fix": "syncpack fix-mismatches", "syncpack:update": "syncpack update", "test": "turbo run test", - "test:run": "turbo run test:run" + "test:run": "turbo run test:run", + "test:watch": "run-p test dev:test" }, "engines": { "node": "=20" diff --git a/packages/grading/package.json b/packages/grading/package.json index 7aca23312f..f3f0f394a3 100644 --- a/packages/grading/package.json +++ b/packages/grading/package.json @@ -1,6 +1,6 @@ { "name": "@klicker-uzh/grading", - "version": "3.3.0-alpha.4", + "version": "3.3.0-alpha.7", "license": "AGPL-3.0", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/graphql/package.json b/packages/graphql/package.json index 642bc2868d..d808ddc853 100644 --- a/packages/graphql/package.json +++ b/packages/graphql/package.json @@ -1,6 +1,6 @@ { "name": "@klicker-uzh/graphql", - "version": "3.3.0-alpha.4", + "version": "3.3.0-alpha.7", "license": "AGPL-3.0", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -28,7 +28,6 @@ "graphql-yoga": "3.9.1", "jsonwebtoken": "9.0.2", "mathjs": "11.9.1", - "mongodb": "5.7.0", "node-schedule": "2.1.1", "nodemailer": "6.9.15", "remeda": "2.15.0", diff --git a/packages/graphql/src/graphql/ops/MRequestMigrationToken.graphql b/packages/graphql/src/graphql/ops/MRequestMigrationToken.graphql deleted file mode 100644 index 592f65c581..0000000000 --- a/packages/graphql/src/graphql/ops/MRequestMigrationToken.graphql +++ /dev/null @@ -1,3 +0,0 @@ -mutation RequestMigrationToken($email: String!) { - requestMigrationToken(email: $email) -} diff --git a/packages/graphql/src/graphql/ops/MTriggerMigration.graphql b/packages/graphql/src/graphql/ops/MTriggerMigration.graphql deleted file mode 100644 index 9e1a9b1d2e..0000000000 --- a/packages/graphql/src/graphql/ops/MTriggerMigration.graphql +++ /dev/null @@ -1,3 +0,0 @@ -mutation TriggerMigration($token: String!) { - triggerMigration(token: $token) -} diff --git a/packages/graphql/src/lib/mongo.ts b/packages/graphql/src/lib/mongo.ts deleted file mode 100644 index 37832b1b86..0000000000 --- a/packages/graphql/src/lib/mongo.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Db, MongoClient } from 'mongodb' - -let mongo: Db - -async function getMongoDB() { - if (!mongo) { - try { - const mongoURL = process.env.MIGRATION_MONGO_CONNECTION_STRING as string - - const mongoClient = new MongoClient(mongoURL) - await mongoClient.connect() - - mongo = mongoClient.db('klicker-prod') - } catch (e) { - console.error(e) - } - } - - return mongo -} - -export default getMongoDB diff --git a/packages/graphql/src/lib/util.ts b/packages/graphql/src/lib/util.ts index 8939146989..ea58f11edf 100644 --- a/packages/graphql/src/lib/util.ts +++ b/packages/graphql/src/lib/util.ts @@ -126,51 +126,3 @@ const findEarliestDueDate = ( ) ?.toDate() } - -export async function sendEmailMigrationNotification( - email: string, - templateId: string -) { - const LISTMONK_AUTH = { - username: process.env.LISTMONK_USER as string, - password: process.env.LISTMONK_PASS as string, - } - - try { - // add the user as a subscriber to enable sending emails via listmonk - await axios.post( - `${process.env.LISTMONK_URL}/api/subscribers`, - { - email: email, - name: email, - status: 'enabled', - preconfirm_subscriptions: true, - }, - { auth: LISTMONK_AUTH } - ) - } catch (e: any) { - console.error(e) - // if (e.response.status !== 409) { - // context.error(e) - // } - } - - try { - const result = await axios.post( - `${process.env.LISTMONK_URL}/api/tx`, - { - subscriber_emails: [email], - template_id: Number(templateId), - }, - { auth: LISTMONK_AUTH } - ) - - console.log(result) - - return result - } catch (e) { - console.error(e) - } - - return null -} diff --git a/packages/graphql/src/ops.schema.json b/packages/graphql/src/ops.schema.json index 0116bdd9b7..713cf07f93 100644 --- a/packages/graphql/src/ops.schema.json +++ b/packages/graphql/src/ops.schema.json @@ -14168,35 +14168,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "requestMigrationToken", - "description": null, - "args": [ - { - "name": "email", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "resolveFeedback", "description": null, @@ -14711,35 +14682,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "triggerMigration", - "description": null, - "args": [ - { - "name": "token", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "unpublishGroupActivity", "description": null, diff --git a/packages/graphql/src/ops.ts b/packages/graphql/src/ops.ts index 8544c023f4..584b83ec0f 100644 --- a/packages/graphql/src/ops.ts +++ b/packages/graphql/src/ops.ts @@ -1019,7 +1019,6 @@ export type Mutation = { publishScheduledActivities: Scalars['Boolean']['output']; rateElement?: Maybe; renameParticipantGroup?: Maybe; - requestMigrationToken?: Maybe; resolveFeedback?: Maybe; respondToElementStack?: Maybe; respondToFeedback?: Maybe; @@ -1032,7 +1031,6 @@ export type Mutation = { subscribeToPush?: Maybe; toggleArchiveCourse?: Maybe; toggleIsArchived?: Maybe>; - triggerMigration?: Maybe; unpublishGroupActivity?: Maybe; unpublishMicroLearning?: Maybe; unpublishPracticeQuiz?: Maybe; @@ -1576,11 +1574,6 @@ export type MutationRenameParticipantGroupArgs = { }; -export type MutationRequestMigrationTokenArgs = { - email: Scalars['String']['input']; -}; - - export type MutationResolveFeedbackArgs = { id: Scalars['Int']['input']; isResolved: Scalars['Boolean']['input']; @@ -1641,11 +1634,6 @@ export type MutationToggleIsArchivedArgs = { }; -export type MutationTriggerMigrationArgs = { - token: Scalars['String']['input']; -}; - - export type MutationUnpublishGroupActivityArgs = { id: Scalars['String']['input']; }; @@ -3237,13 +3225,6 @@ export type RenameParticipantGroupMutationVariables = Exact<{ export type RenameParticipantGroupMutation = { __typename?: 'Mutation', renameParticipantGroup?: { __typename?: 'ParticipantGroup', id: string, name: string } | null }; -export type RequestMigrationTokenMutationVariables = Exact<{ - email: Scalars['String']['input']; -}>; - - -export type RequestMigrationTokenMutation = { __typename?: 'Mutation', requestMigrationToken?: boolean | null }; - export type ResolveFeedbackMutationVariables = Exact<{ id: Scalars['Int']['input']; isResolved: Scalars['Boolean']['input']; @@ -3334,13 +3315,6 @@ export type ToggleIsArchivedMutationVariables = Exact<{ export type ToggleIsArchivedMutation = { __typename?: 'Mutation', toggleIsArchived?: Array<{ __typename: 'ArchivedElement', id: number, isArchived: boolean }> | null }; -export type TriggerMigrationMutationVariables = Exact<{ - token: Scalars['String']['input']; -}>; - - -export type TriggerMigrationMutation = { __typename?: 'Mutation', triggerMigration?: boolean | null }; - export type UnpublishGroupActivityMutationVariables = Exact<{ id: Scalars['String']['input']; }>; @@ -4009,7 +3983,6 @@ export const PublishMicroLearningDocument = {"kind":"Document","definitions":[{" export const PublishPracticeQuizDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"PublishPracticeQuiz"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"publishPracticeQuiz"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]} as unknown as DocumentNode; export const RateElementDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RateElement"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"elementInstanceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"elementId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"rating"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"rateElement"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"elementInstanceId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"elementInstanceId"}}},{"kind":"Argument","name":{"kind":"Name","value":"elementId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"elementId"}}},{"kind":"Argument","name":{"kind":"Name","value":"rating"},"value":{"kind":"Variable","name":{"kind":"Name","value":"rating"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"upvote"}},{"kind":"Field","name":{"kind":"Name","value":"downvote"}},{"kind":"Field","name":{"kind":"Name","value":"feedback"}}]}}]}}]} as unknown as DocumentNode; export const RenameParticipantGroupDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RenameParticipantGroup"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"groupId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"renameParticipantGroup"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"groupId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"groupId"}}},{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; -export const RequestMigrationTokenDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RequestMigrationToken"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"email"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"requestMigrationToken"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"email"},"value":{"kind":"Variable","name":{"kind":"Name","value":"email"}}}]}]}}]} as unknown as DocumentNode; export const ResolveFeedbackDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ResolveFeedback"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isResolved"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"resolveFeedback"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"isResolved"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isResolved"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"isPublished"}},{"kind":"Field","name":{"kind":"Name","value":"isPinned"}},{"kind":"Field","name":{"kind":"Name","value":"isResolved"}},{"kind":"Field","name":{"kind":"Name","value":"content"}},{"kind":"Field","name":{"kind":"Name","value":"votes"}}]}}]}}]} as unknown as DocumentNode; export const RespondToElementStackDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RespondToElementStack"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stackId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"responses"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"StackResponseInput"}}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stackAnswerTime"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"respondToElementStack"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"stackId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stackId"}}},{"kind":"Argument","name":{"kind":"Name","value":"courseId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseId"}}},{"kind":"Argument","name":{"kind":"Name","value":"responses"},"value":{"kind":"Variable","name":{"kind":"Name","value":"responses"}}},{"kind":"Argument","name":{"kind":"Name","value":"stackAnswerTime"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stackAnswerTime"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"StackFeedbackEvaluations"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"StackFeedbackEvaluations"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"StackFeedback"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"evaluations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ChoicesInstanceEvaluation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"elementType"}},{"kind":"Field","name":{"kind":"Name","value":"instanceId"}},{"kind":"Field","name":{"kind":"Name","value":"pointsMultiplier"}},{"kind":"Field","name":{"kind":"Name","value":"explanation"}},{"kind":"Field","name":{"kind":"Name","value":"feedbacks"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ix"}},{"kind":"Field","name":{"kind":"Name","value":"feedback"}},{"kind":"Field","name":{"kind":"Name","value":"correct"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}},{"kind":"Field","name":{"kind":"Name","value":"choices"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ix"}},{"kind":"Field","name":{"kind":"Name","value":"count"}}]}},{"kind":"Field","name":{"kind":"Name","value":"numAnswers"}},{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"xp"}},{"kind":"Field","name":{"kind":"Name","value":"pointsAwarded"}},{"kind":"Field","name":{"kind":"Name","value":"percentile"}},{"kind":"Field","name":{"kind":"Name","value":"newPointsFrom"}},{"kind":"Field","name":{"kind":"Name","value":"xpAwarded"}},{"kind":"Field","name":{"kind":"Name","value":"newXpFrom"}},{"kind":"Field","name":{"kind":"Name","value":"correctness"}},{"kind":"Field","name":{"kind":"Name","value":"lastResponse"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"choices"}}]}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NumericalInstanceEvaluation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"elementType"}},{"kind":"Field","name":{"kind":"Name","value":"instanceId"}},{"kind":"Field","name":{"kind":"Name","value":"pointsMultiplier"}},{"kind":"Field","name":{"kind":"Name","value":"explanation"}},{"kind":"Field","name":{"kind":"Name","value":"feedbacks"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ix"}},{"kind":"Field","name":{"kind":"Name","value":"feedback"}},{"kind":"Field","name":{"kind":"Name","value":"correct"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}},{"kind":"Field","name":{"kind":"Name","value":"numAnswers"}},{"kind":"Field","name":{"kind":"Name","value":"responses"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"count"}}]}},{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"xp"}},{"kind":"Field","name":{"kind":"Name","value":"pointsAwarded"}},{"kind":"Field","name":{"kind":"Name","value":"percentile"}},{"kind":"Field","name":{"kind":"Name","value":"newPointsFrom"}},{"kind":"Field","name":{"kind":"Name","value":"xpAwarded"}},{"kind":"Field","name":{"kind":"Name","value":"newXpFrom"}},{"kind":"Field","name":{"kind":"Name","value":"solutionRanges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"min"}},{"kind":"Field","name":{"kind":"Name","value":"max"}}]}},{"kind":"Field","name":{"kind":"Name","value":"lastResponse"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}},{"kind":"Field","name":{"kind":"Name","value":"correctness"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FreeTextInstanceEvaluation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"instanceId"}},{"kind":"Field","name":{"kind":"Name","value":"elementType"}},{"kind":"Field","name":{"kind":"Name","value":"pointsMultiplier"}},{"kind":"Field","name":{"kind":"Name","value":"explanation"}},{"kind":"Field","name":{"kind":"Name","value":"feedbacks"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ix"}},{"kind":"Field","name":{"kind":"Name","value":"feedback"}},{"kind":"Field","name":{"kind":"Name","value":"correct"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}},{"kind":"Field","name":{"kind":"Name","value":"numAnswers"}},{"kind":"Field","name":{"kind":"Name","value":"answers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"count"}}]}},{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"xp"}},{"kind":"Field","name":{"kind":"Name","value":"pointsAwarded"}},{"kind":"Field","name":{"kind":"Name","value":"percentile"}},{"kind":"Field","name":{"kind":"Name","value":"newPointsFrom"}},{"kind":"Field","name":{"kind":"Name","value":"xpAwarded"}},{"kind":"Field","name":{"kind":"Name","value":"newXpFrom"}},{"kind":"Field","name":{"kind":"Name","value":"solutions"}},{"kind":"Field","name":{"kind":"Name","value":"lastResponse"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}},{"kind":"Field","name":{"kind":"Name","value":"correctness"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FlashcardInstanceEvaluation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"instanceId"}},{"kind":"Field","name":{"kind":"Name","value":"elementType"}},{"kind":"Field","name":{"kind":"Name","value":"pointsMultiplier"}},{"kind":"Field","name":{"kind":"Name","value":"explanation"}},{"kind":"Field","name":{"kind":"Name","value":"feedbacks"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ix"}},{"kind":"Field","name":{"kind":"Name","value":"feedback"}},{"kind":"Field","name":{"kind":"Name","value":"correct"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}},{"kind":"Field","name":{"kind":"Name","value":"numAnswers"}},{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"xp"}},{"kind":"Field","name":{"kind":"Name","value":"pointsAwarded"}},{"kind":"Field","name":{"kind":"Name","value":"percentile"}},{"kind":"Field","name":{"kind":"Name","value":"newPointsFrom"}},{"kind":"Field","name":{"kind":"Name","value":"xpAwarded"}},{"kind":"Field","name":{"kind":"Name","value":"newXpFrom"}},{"kind":"Field","name":{"kind":"Name","value":"lastResponse"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"correctness"}}]}},{"kind":"Field","name":{"kind":"Name","value":"correctness"}}]}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ContentInstanceEvaluation"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"instanceId"}},{"kind":"Field","name":{"kind":"Name","value":"elementType"}},{"kind":"Field","name":{"kind":"Name","value":"pointsMultiplier"}},{"kind":"Field","name":{"kind":"Name","value":"explanation"}},{"kind":"Field","name":{"kind":"Name","value":"feedbacks"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"ix"}},{"kind":"Field","name":{"kind":"Name","value":"feedback"}},{"kind":"Field","name":{"kind":"Name","value":"correct"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}},{"kind":"Field","name":{"kind":"Name","value":"numAnswers"}},{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"xp"}},{"kind":"Field","name":{"kind":"Name","value":"pointsAwarded"}},{"kind":"Field","name":{"kind":"Name","value":"percentile"}},{"kind":"Field","name":{"kind":"Name","value":"newPointsFrom"}},{"kind":"Field","name":{"kind":"Name","value":"xpAwarded"}},{"kind":"Field","name":{"kind":"Name","value":"newXpFrom"}},{"kind":"Field","name":{"kind":"Name","value":"lastResponse"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"viewed"}}]}},{"kind":"Field","name":{"kind":"Name","value":"correctness"}}]}}]}}]}}]} as unknown as DocumentNode; export const RespondToFeedbackDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RespondToFeedback"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"responseContent"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"respondToFeedback"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"responseContent"},"value":{"kind":"Variable","name":{"kind":"Name","value":"responseContent"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"isPublished"}},{"kind":"Field","name":{"kind":"Name","value":"isPinned"}},{"kind":"Field","name":{"kind":"Name","value":"isResolved"}},{"kind":"Field","name":{"kind":"Name","value":"content"}},{"kind":"Field","name":{"kind":"Name","value":"votes"}},{"kind":"Field","name":{"kind":"Name","value":"resolvedAt"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"responses"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"content"}},{"kind":"Field","name":{"kind":"Name","value":"positiveReactions"}},{"kind":"Field","name":{"kind":"Name","value":"negativeReactions"}}]}}]}}]}}]} as unknown as DocumentNode; @@ -4022,7 +3995,6 @@ export const SubmitGroupActivityDecisionsDocument = {"kind":"Document","definiti export const SubscribeToPushDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SubscribeToPush"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"courseId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"subscriptionObject"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SubscriptionObjectInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"subscribeToPush"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"courseId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"courseId"}}},{"kind":"Argument","name":{"kind":"Name","value":"subscriptionObject"},"value":{"kind":"Variable","name":{"kind":"Name","value":"subscriptionObject"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"subscriptions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"endpoint"}}]}}]}}]}}]} as unknown as DocumentNode; export const ToggleArchiveCourseDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ToggleArchiveCourse"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isArchived"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"toggleArchiveCourse"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"isArchived"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isArchived"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"isArchived"}}]}}]}}]} as unknown as DocumentNode; export const ToggleIsArchivedDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ToggleIsArchived"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"questionIds"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"isArchived"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"toggleIsArchived"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"questionIds"},"value":{"kind":"Variable","name":{"kind":"Name","value":"questionIds"}}},{"kind":"Argument","name":{"kind":"Name","value":"isArchived"},"value":{"kind":"Variable","name":{"kind":"Name","value":"isArchived"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"isArchived"}}]}}]}}]} as unknown as DocumentNode; -export const TriggerMigrationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"TriggerMigration"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"token"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"triggerMigration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"token"},"value":{"kind":"Variable","name":{"kind":"Name","value":"token"}}}]}]}}]} as unknown as DocumentNode; export const UnpublishGroupActivityDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UnpublishGroupActivity"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"unpublishGroupActivity"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]} as unknown as DocumentNode; export const UnpublishMicroLearningDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UnpublishMicroLearning"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"unpublishMicroLearning"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"numOfStacks"}}]}}]}}]} as unknown as DocumentNode; export const UnpublishPracticeQuizDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UnpublishPracticeQuiz"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"unpublishPracticeQuiz"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"numOfStacks"}}]}}]}}]} as unknown as DocumentNode; diff --git a/packages/graphql/src/public/client.json b/packages/graphql/src/public/client.json index 09dd33212c..22607149eb 100644 --- a/packages/graphql/src/public/client.json +++ b/packages/graphql/src/public/client.json @@ -78,7 +78,6 @@ "PublishPracticeQuiz": "33685d50bdf1f3ced515e84647eab6fd00770ca9474760a8459a57849f1a04e9", "RateElement": "76e7fcf8f292b9227c4505f7e55c193fc8e55a39cca3dcc5e68d15c0a4e9c952", "RenameParticipantGroup": "e909972c210ced0bff2f94496e2f71d87e9514f5b01e61eca0b66327d843af8a", - "RequestMigrationToken": "27743950d25589484d14d9b19d39130a63085a49820d77e91ad9365096c4423d", "ResolveFeedback": "1462d426a28839917a0651fdb669bea4fa1962e61b375a627f210c618dafbf4d", "RespondToElementStack": "6d6a9d682fec4508a735ef2464c00945d30bc3148d8f33a64a624acf526113cb", "RespondToFeedback": "827ab68df5f3d9cdf820f9da66e56af0c1e1cdad1091386d20a37fe8ad667317", @@ -91,7 +90,6 @@ "SubscribeToPush": "c87b8f1775dd85c77a6a7a774c8e4885093f02fc4404a12783521d9e2fb77add", "ToggleArchiveCourse": "924d889c64995d6da7a84bf1971251ac39b6ba53bd6c6e7de2a54050ecf949b2", "ToggleIsArchived": "9f5e4352af85e66fb713b4b23e1dd9c4969cd918a3fbf67c7e2d9951d92f8ede", - "TriggerMigration": "70f0a8db37214243f7025605861519bb4577a917da4bb0d22ff8ec858f209427", "UnpublishGroupActivity": "5b05cccedeb339da3ef5c3d2ee9bbde86421b22ca49d014a7b263b2c0fc5618c", "UnpublishMicroLearning": "1aa15a5c29ec6bc3cc129d439879524fc04998dd6fd57f318ef169e1831a9a2b", "UnpublishPracticeQuiz": "51ad68d7764cc9efff1d8885538bfe1d362dd6983e2e89d7000eba7f221573b5", diff --git a/packages/graphql/src/public/schema.graphql b/packages/graphql/src/public/schema.graphql index c88f03e994..b89884cd6e 100644 --- a/packages/graphql/src/public/schema.graphql +++ b/packages/graphql/src/public/schema.graphql @@ -939,7 +939,6 @@ type Mutation { publishScheduledActivities: Boolean! rateElement(elementId: Int!, elementInstanceId: Int!, rating: Int!): ElementFeedback renameParticipantGroup(groupId: String!, name: String!): ParticipantGroup - requestMigrationToken(email: String!): Boolean resolveFeedback(id: Int!, isResolved: Boolean!): Feedback respondToElementStack(courseId: String!, responses: [StackResponseInput!]!, stackAnswerTime: Int!, stackId: Int!): StackFeedback respondToFeedback(id: Int!, responseContent: String!): Feedback @@ -952,7 +951,6 @@ type Mutation { subscribeToPush(courseId: String!, subscriptionObject: SubscriptionObjectInput!): Participation toggleArchiveCourse(id: String!, isArchived: Boolean!): Course toggleIsArchived(isArchived: Boolean!, questionIds: [Int!]!): [ArchivedElement!] - triggerMigration(token: String!): Boolean unpublishGroupActivity(id: String!): GroupActivity unpublishMicroLearning(id: String!): MicroLearning unpublishPracticeQuiz(id: String!): PracticeQuiz diff --git a/packages/graphql/src/public/server.json b/packages/graphql/src/public/server.json index 2ae0b010db..7d49dd430f 100644 --- a/packages/graphql/src/public/server.json +++ b/packages/graphql/src/public/server.json @@ -78,7 +78,6 @@ "33685d50bdf1f3ced515e84647eab6fd00770ca9474760a8459a57849f1a04e9": "mutation PublishPracticeQuiz($id: String!) {\n publishPracticeQuiz(id: $id) {\n id\n name\n displayName\n status\n __typename\n }\n}", "76e7fcf8f292b9227c4505f7e55c193fc8e55a39cca3dcc5e68d15c0a4e9c952": "mutation RateElement($elementInstanceId: Int!, $elementId: Int!, $rating: Int!) {\n rateElement(\n elementInstanceId: $elementInstanceId\n elementId: $elementId\n rating: $rating\n ) {\n id\n upvote\n downvote\n feedback\n __typename\n }\n}", "e909972c210ced0bff2f94496e2f71d87e9514f5b01e61eca0b66327d843af8a": "mutation RenameParticipantGroup($groupId: String!, $name: String!) {\n renameParticipantGroup(groupId: $groupId, name: $name) {\n id\n name\n __typename\n }\n}", - "27743950d25589484d14d9b19d39130a63085a49820d77e91ad9365096c4423d": "mutation RequestMigrationToken($email: String!) {\n requestMigrationToken(email: $email)\n}", "1462d426a28839917a0651fdb669bea4fa1962e61b375a627f210c618dafbf4d": "mutation ResolveFeedback($id: Int!, $isResolved: Boolean!) {\n resolveFeedback(id: $id, isResolved: $isResolved) {\n id\n isPublished\n isPinned\n isResolved\n content\n votes\n __typename\n }\n}", "6d6a9d682fec4508a735ef2464c00945d30bc3148d8f33a64a624acf526113cb": "fragment StackFeedbackEvaluations on StackFeedback {\n evaluations {\n __typename\n ... on ChoicesInstanceEvaluation {\n __typename\n elementType\n instanceId\n pointsMultiplier\n explanation\n feedbacks {\n ix\n feedback\n correct\n value\n __typename\n }\n choices {\n ix\n count\n __typename\n }\n numAnswers\n score\n xp\n pointsAwarded\n percentile\n newPointsFrom\n xpAwarded\n newXpFrom\n correctness\n lastResponse {\n __typename\n choices\n }\n }\n ... on NumericalInstanceEvaluation {\n __typename\n elementType\n instanceId\n pointsMultiplier\n explanation\n feedbacks {\n ix\n feedback\n correct\n value\n __typename\n }\n numAnswers\n responses {\n value\n count\n __typename\n }\n score\n xp\n pointsAwarded\n percentile\n newPointsFrom\n xpAwarded\n newXpFrom\n solutionRanges {\n __typename\n min\n max\n }\n lastResponse {\n __typename\n value\n }\n correctness\n }\n ... on FreeTextInstanceEvaluation {\n instanceId\n elementType\n pointsMultiplier\n explanation\n feedbacks {\n ix\n feedback\n correct\n value\n __typename\n }\n numAnswers\n answers {\n value\n count\n __typename\n }\n score\n xp\n pointsAwarded\n percentile\n newPointsFrom\n xpAwarded\n newXpFrom\n solutions\n lastResponse {\n __typename\n value\n }\n correctness\n __typename\n }\n ... on FlashcardInstanceEvaluation {\n instanceId\n elementType\n pointsMultiplier\n explanation\n feedbacks {\n ix\n feedback\n correct\n value\n __typename\n }\n numAnswers\n score\n xp\n pointsAwarded\n percentile\n newPointsFrom\n xpAwarded\n newXpFrom\n lastResponse {\n __typename\n correctness\n }\n correctness\n __typename\n }\n ... on ContentInstanceEvaluation {\n instanceId\n elementType\n pointsMultiplier\n explanation\n feedbacks {\n ix\n feedback\n correct\n value\n __typename\n }\n numAnswers\n score\n xp\n pointsAwarded\n percentile\n newPointsFrom\n xpAwarded\n newXpFrom\n lastResponse {\n __typename\n viewed\n }\n correctness\n __typename\n }\n }\n __typename\n}\nmutation RespondToElementStack($stackId: Int!, $courseId: String!, $responses: [StackResponseInput!]!, $stackAnswerTime: Int!) {\n respondToElementStack(\n stackId: $stackId\n courseId: $courseId\n responses: $responses\n stackAnswerTime: $stackAnswerTime\n ) {\n id\n status\n score\n ...StackFeedbackEvaluations\n __typename\n }\n}", "827ab68df5f3d9cdf820f9da66e56af0c1e1cdad1091386d20a37fe8ad667317": "mutation RespondToFeedback($id: Int!, $responseContent: String!) {\n respondToFeedback(id: $id, responseContent: $responseContent) {\n id\n isPublished\n isPinned\n isResolved\n content\n votes\n resolvedAt\n createdAt\n responses {\n id\n content\n positiveReactions\n negativeReactions\n __typename\n }\n __typename\n }\n}", @@ -91,7 +90,6 @@ "c87b8f1775dd85c77a6a7a774c8e4885093f02fc4404a12783521d9e2fb77add": "mutation SubscribeToPush($courseId: String!, $subscriptionObject: SubscriptionObjectInput!) {\n subscribeToPush(courseId: $courseId, subscriptionObject: $subscriptionObject) {\n id\n subscriptions {\n id\n endpoint\n __typename\n }\n __typename\n }\n}", "924d889c64995d6da7a84bf1971251ac39b6ba53bd6c6e7de2a54050ecf949b2": "mutation ToggleArchiveCourse($id: String!, $isArchived: Boolean!) {\n toggleArchiveCourse(id: $id, isArchived: $isArchived) {\n id\n isArchived\n __typename\n }\n}", "9f5e4352af85e66fb713b4b23e1dd9c4969cd918a3fbf67c7e2d9951d92f8ede": "mutation ToggleIsArchived($questionIds: [Int!]!, $isArchived: Boolean!) {\n toggleIsArchived(questionIds: $questionIds, isArchived: $isArchived) {\n __typename\n id\n isArchived\n }\n}", - "70f0a8db37214243f7025605861519bb4577a917da4bb0d22ff8ec858f209427": "mutation TriggerMigration($token: String!) {\n triggerMigration(token: $token)\n}", "5b05cccedeb339da3ef5c3d2ee9bbde86421b22ca49d014a7b263b2c0fc5618c": "mutation UnpublishGroupActivity($id: String!) {\n unpublishGroupActivity(id: $id) {\n id\n name\n displayName\n status\n __typename\n }\n}", "1aa15a5c29ec6bc3cc129d439879524fc04998dd6fd57f318ef169e1831a9a2b": "mutation UnpublishMicroLearning($id: String!) {\n unpublishMicroLearning(id: $id) {\n id\n name\n displayName\n status\n numOfStacks\n __typename\n }\n}", "51ad68d7764cc9efff1d8885538bfe1d362dd6983e2e89d7000eba7f221573b5": "mutation UnpublishPracticeQuiz($id: String!) {\n unpublishPracticeQuiz(id: $id) {\n id\n name\n displayName\n status\n numOfStacks\n __typename\n }\n}", diff --git a/packages/graphql/src/schema/mutation.ts b/packages/graphql/src/schema/mutation.ts index c2d7e2bb1e..25b707f1bc 100644 --- a/packages/graphql/src/schema/mutation.ts +++ b/packages/graphql/src/schema/mutation.ts @@ -7,7 +7,6 @@ import * as FeedbackService from '../services/feedbacks.js' import * as GroupService from '../services/groups.js' import * as LiveQuizService from '../services/liveQuizzes.js' import * as MicroLearningService from '../services/microLearning.js' -import * as MigrationService from '../services/migration.js' import * as NotificationService from '../services/notifications.js' import * as ParticipantService from '../services/participants.js' import * as PracticeQuizService from '../services/practiceQuizzes.js' @@ -1497,26 +1496,6 @@ export const Mutation = builder.mutationType({ // ----- USER OWNER OPERATIONS ----- // #region - requestMigrationToken: t.withAuth(asUserOwner).boolean({ - nullable: true, - args: { - email: t.arg.string({ required: true }), - }, - resolve(_, args, ctx) { - return MigrationService.requestMigrationToken(args, ctx) - }, - }), - - triggerMigration: t.withAuth(asUserOwner).boolean({ - nullable: true, - args: { - token: t.arg.string({ required: true }), - }, - resolve(_, args, ctx) { - return MigrationService.triggerMigration(args, ctx) - }, - }), - createUserLogin: t.withAuth(asUserOwner).field({ nullable: true, type: UserLogin, diff --git a/packages/graphql/src/scripts/2024_10_31_fix_choices_options.ts b/packages/graphql/src/scripts/2024_10_31_fix_choices_options.ts new file mode 100644 index 0000000000..d9a7797d66 --- /dev/null +++ b/packages/graphql/src/scripts/2024_10_31_fix_choices_options.ts @@ -0,0 +1,241 @@ +import { ElementType, PrismaClient } from '@klicker-uzh/prisma' + +interface Choice { + ix: number + [key: string]: any +} + +interface ValidationResult { + hasValidIndices: boolean + hasDuplicateIndices: boolean + hasGaps: boolean + needsReordering: boolean +} + +function validateChoices( + choices: Choice[], + entityType: string, + entityId: number, + verbose: boolean +): ValidationResult { + const hasValidIndices = choices.every((c) => typeof c.ix === 'number') + const hasDuplicateIndices = + new Set(choices.map((c) => c.ix)).size !== choices.length + const hasGaps = !choices.every((_, index) => + choices.some((c) => c.ix === index) + ) + const needsReordering = choices.some((c, index) => c.ix !== index) + + if ((verbose && !hasValidIndices) || hasDuplicateIndices || hasGaps) { + console.error( + `${entityType} ${entityId} has invalid choices configuration:` + ) + if (!hasValidIndices) console.error(' - Some indices are not numbers') + if (hasDuplicateIndices) console.error(' - Contains duplicate indices') + if (hasGaps) console.error(' - Has gaps in index sequence') + console.error('Choices:', choices) + } + + return { hasValidIndices, hasDuplicateIndices, hasGaps, needsReordering } +} + +async function run() { + const prisma = new PrismaClient() + const verbose = true + + // ! VALIDATION + // fetch all elements + const es = await prisma.element.findMany() + + // fetch all element instances + const eis = await prisma.elementInstance.findMany({ + include: { responses: true, detailResponses: true }, + }) + + // fetch all question instances + const qis = await prisma.questionInstance.findMany() + + // loop over all elements, filter for choices questions and check if choices are in order + let e_errors = 0 + let e_updates = 0 + for (const e of es) { + if ( + e.type === ElementType.SC || + e.type === ElementType.MC || + e.type === ElementType.KPRIM + ) { + const choices = e.options.choices + const { needsReordering } = validateChoices( + choices, + 'Element', + e.id, + verbose + ) + + if (needsReordering) { + e_errors += 1 + + if (verbose) { + console.error( + `Element ${e.id} has choices out of order: ${choices + .map((c) => c.ix) + .join(', ')}` + ) + } + + // update the element choices + const newChoices = choices.map((c, index) => ({ + ...c, + ix: index, + })) + + console.log('OLD CHOICES:') + console.log(choices) + console.log('NEW CHOICES:') + console.log(newChoices) + e_updates += 1 + + // TODO: uncomment to trigger element updates + // await prisma.element.update({ + // where: { id: e.id }, + // data: { + // options: { + // ...e.options, + // choices: newChoices, + // }, + // }, + // }) + } + } + } + + // loop over all element instances, filter for choices instances, check if choices are in order + let ei_errors = 0 + let ei_updates = 0 + for (const ei of eis) { + if ( + ei.elementType === ElementType.SC || + ei.elementType === ElementType.MC || + ei.elementType === ElementType.KPRIM + ) { + const choices = ei.elementData.options.choices + const { needsReordering } = validateChoices( + choices, + 'ElementInstance', + ei.id, + verbose + ) + + if (needsReordering) { + ei_errors += 1 + + if (verbose) { + console.error( + `ElementInstance ${ei.id} has choices out of order: ${choices + .map((c) => c.ix) + .join( + ', ' + )} with ${ei.responses.length} responses and ${ei.detailResponses.length} detail responses` + ) + } + + // update the indices on the element instances + const newChoices = choices.map((c, index) => ({ + ...c, + ix: index, + })) + + console.log('OLD CHOICES:') + console.log(choices) + console.log('NEW CHOICES:') + console.log(newChoices) + ei_updates += 1 + + // TODO: uncomment to trigger element instance updates + // await prisma.elementInstance.update({ + // where: { id: ei.id }, + // data: { + // elementData: { + // ...ei.elementData, + // options: { + // ...ei.elementData.options, + // choices: newChoices, + // }, + // }, + // }, + // }) + } + } + } + + let qi_errors = 0 + let qi_updates = 0 + for (const qi of qis) { + if ( + qi.questionData.type === ElementType.SC || + qi.questionData.type === ElementType.MC || + qi.questionData.type === ElementType.KPRIM + ) { + const choices = qi.questionData.options.choices + const { needsReordering } = validateChoices( + choices, + 'QuestionInstance', + qi.id, + verbose + ) + + if (needsReordering) { + qi_errors += 1 + + if (verbose) { + console.error( + `QuestionInstance ${qi.id} has choices out of order: ${choices + .map((c) => c.ix) + .join(', ')}` + ) + } + + // update the indices on the question instances + const newChoices = choices.map((c, index) => ({ + ...c, + ix: index, + })) + + console.log('OLD CHOICES:') + console.log(choices) + console.log('NEW CHOICES:') + console.log(newChoices) + qi_updates += 1 + + // TODO: uncomment to trigger question instance updates + // await prisma.questionInstance.update({ + // where: { id: qi.id }, + // data: { + // questionData: { + // ...qi.questionData, + // options: { + // ...qi.questionData.options, + // choices: newChoices, + // }, + // }, + // }, + // }) + } + } + } + + console.log('Done checking choices') + console.log('Found', e_errors, 'elements with out of order choices') + console.log('Found', ei_errors, 'element instances with out of order choices') + console.log( + 'Found', + qi_errors, + 'question instances with out of order choices' + ) + + console.log('Updated', e_updates, 'elements') + console.log('Updated', ei_updates, 'element instances') + console.log('Updated', qi_updates, 'question instances') +} + +await run() diff --git a/packages/graphql/src/services/migration.ts b/packages/graphql/src/services/migration.ts deleted file mode 100644 index 9556bfda80..0000000000 --- a/packages/graphql/src/services/migration.ts +++ /dev/null @@ -1,182 +0,0 @@ -import axios from 'axios' -import JWT from 'jsonwebtoken' -import normalizeEmail from 'validator/lib/normalizeEmail.js' - -import { ServiceBusClient } from '@azure/service-bus' -import type { ContextWithUser } from '../lib/context.js' -import getMongoDB from '../lib/mongo.js' -import { - sendEmailMigrationNotification, - sendTeamsNotifications, -} from '../lib/util.js' - -interface RequestMigrationTokenArgs { - email: string -} - -export async function requestMigrationToken( - args: RequestMigrationTokenArgs, - ctx: ContextWithUser -) { - const userData = await ctx.prisma.user.findUnique({ - where: { - id: ctx.user.sub, - }, - }) - - if (!userData) return false - - const db = await getMongoDB() - - // we used normalization for emails in the old KlickerUZH - // if they enter the email address unnormalized, we still want to try matching against the normalized version - const matchingUsers = await db - .collection('users') - .find({ email: args.email.toLowerCase() }) - .toArray() - - const matchingUsersNormalized = await db - .collection('users') - // @ts-ignore - .find({ email: normalizeEmail(args.email) }) - .toArray() - - const oldEmail = - matchingUsers?.[0]?.email ?? matchingUsersNormalized?.[0]?.email - - if (!oldEmail) { - await sendEmailMigrationNotification( - userData.email, - process.env.LISTMONK_TEMPLATE_MIGRATION_EMAIL_NOT_AVAILABLE as string - ) - await sendTeamsNotifications( - 'graphql/migration', - `[${process.env.NODE_ENV}] Migration Failed for E-Mail ${args.email} in v2 with Edu-ID ${userData.email} (v3). V2 account not found.` - ) - - throw new Error(`No matching V2 user found for ${args.email}`) - } - - const migrationToken = JWT.sign( - { - sub: ctx.user.sub, - originalEmail: oldEmail, - }, - process.env.MIGRATION_SECRET as string, - { - expiresIn: '7d', - } - ) - - const migrationLink = `https://manage${ - process.env.COOKIE_DOMAIN - }/migration?token=${encodeURIComponent(migrationToken)}` - - console.log(migrationLink) - - await sendTeamsNotifications( - 'graphql/migration', - `[${process.env.NODE_ENV}] Migration Requested for E-Mail ${oldEmail} in v2 with Edu-ID ${userData.email} (v3), Link: ${migrationLink}` - ) - - const LISTMONK_AUTH = { - username: process.env.LISTMONK_USER as string, - password: process.env.LISTMONK_PASS as string, - } - - try { - // add the user as a subscriber to enable sending emails via listmonk - await axios.post( - `${process.env.LISTMONK_URL}/api/subscribers`, - { - email: oldEmail, - name: oldEmail, - status: 'enabled', - preconfirm_subscriptions: true, - }, - { auth: LISTMONK_AUTH } - ) - } catch (e: any) { - if (e.response.status !== 409) { - console.error(e) - return false - } - } - - try { - // send the migration link via email - await axios.post( - `${process.env.LISTMONK_URL}/api/tx`, - { - subscriber_emails: [oldEmail], - template_id: Number(process.env.LISTMONK_TEMPLATE_MIGRATION_REQUEST), - data: { migrationLink, newAccountEmail: userData.email }, - }, - { auth: LISTMONK_AUTH } - ) - } catch (e) { - console.error(e) - return false - } - - return true -} - -interface TriggerMigrationArgs { - token: string -} - -export async function triggerMigration( - args: TriggerMigrationArgs, - ctx: ContextWithUser -) { - try { - const token = JWT.verify( - args.token, - process.env.MIGRATION_SECRET as string - ) as { - sub: string - originalEmail: string - } - - if (!token) return false - - // if the user generating the token is not the same as the user currently logged in, exit - if (token.sub !== ctx.user.sub) return false - - const user = await ctx.prisma.user.findUnique({ - where: { - id: token.sub, - }, - }) - - if (!user) return false - - // create an azure service bus connection to post the migration message for further processing with azure functions - const sb = new ServiceBusClient( - process.env.MIGRATION_SERVICE_BUS_CONNECTION_STRING as string, - {} - ) - - const sbSender = sb.createSender( - process.env.MIGRATION_SERVICE_BUS_QUEUE_NAME as string - ) - - await sbSender.sendMessages({ - messageId: token.sub, - subject: 'migration', - body: { - newUserId: token.sub, - newEmail: user.email, - originalEmail: token.originalEmail, - }, - }) - - console.log('migration message posted to service bus') - - return true - } catch (e) { - console.error(e) - return false - } -} diff --git a/packages/i18n/messages/de.ts b/packages/i18n/messages/de.ts index 1b9931f3eb..380b386f3f 100644 --- a/packages/i18n/messages/de.ts +++ b/packages/i18n/messages/de.ts @@ -755,7 +755,6 @@ Da die KlickerUZH-App noch nicht im iOS-App-Store verfügbar ist, folgen Sie die questionPool: 'Fragepool', sessions: 'Live-Quizzes', courses: 'Kurse', - migration: 'Migration', generateToken: 'Login-Token generieren', '404Message': 'Die von Ihnen aufgerufene Seite existiert leider nicht. Kehren sie zum Fragepool zurück oder nutzen sie das Menu zur weiteren Navigation.', @@ -899,6 +898,7 @@ Da die KlickerUZH-App noch nicht im iOS-App-Store verfügbar ist, folgen Sie die elementTypes: 'Elementtypen', elementStatus: 'Status', tags: 'Tags', + selectOrType: 'Auswählen oder Eingeben...', untagged: 'Ohne Tags', noTagsAvailable: 'Keine Tags verfügbar', answerFeedbacks: 'Antwortfeedbacks', diff --git a/packages/i18n/messages/en.ts b/packages/i18n/messages/en.ts index f1974039e5..43971454bb 100644 --- a/packages/i18n/messages/en.ts +++ b/packages/i18n/messages/en.ts @@ -757,7 +757,6 @@ Since the KlickerUZH app is not yet available on the iOS App Store, follow these questionPool: 'Question Pool', sessions: 'Live Quizzes', courses: 'Courses', - migration: 'Migration', generateToken: 'Generate login token', '404Message': 'The page you requested does not exist. Please return to the question pool or use the main menu at the top for further navigation.', @@ -901,6 +900,7 @@ Since the KlickerUZH app is not yet available on the iOS App Store, follow these elementTypes: 'Element Types', elementStatus: 'Status', tags: 'Tags', + selectOrType: 'Select or Type...', untagged: 'Untagged', noTagsAvailable: 'No tags available', answerFeedbacks: 'Answer feedbacks', diff --git a/packages/markdown/package.json b/packages/markdown/package.json index f664f7817e..677c4a92e6 100644 --- a/packages/markdown/package.json +++ b/packages/markdown/package.json @@ -1,6 +1,6 @@ { "name": "@klicker-uzh/markdown", - "version": "3.3.0-alpha.4", + "version": "3.3.0-alpha.7", "license": "AGPL-3.0", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/prisma/package.json b/packages/prisma/package.json index c47fbb71f7..c50d858db4 100644 --- a/packages/prisma/package.json +++ b/packages/prisma/package.json @@ -1,6 +1,6 @@ { "name": "@klicker-uzh/prisma", - "version": "3.3.0-alpha.4", + "version": "3.3.0-alpha.7", "license": "AGPL-3.0", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/shared-components/dist/utilities.css b/packages/shared-components/dist/utilities.css index fadbd03996..eda1a99df8 100644 --- a/packages/shared-components/dist/utilities.css +++ b/packages/shared-components/dist/utilities.css @@ -112,10 +112,6 @@ margin-top: 0.5rem } -.mt-4 { - margin-top: 1rem -} - .block { display: block } diff --git a/packages/shared-components/src/hooks/useStudentResponse.ts b/packages/shared-components/src/hooks/useStudentResponse.ts index 2b04b66976..8accac3a2c 100644 --- a/packages/shared-components/src/hooks/useStudentResponse.ts +++ b/packages/shared-components/src/hooks/useStudentResponse.ts @@ -30,8 +30,8 @@ function useStudentResponse({ [element.id]: { type: element.elementData.type as ElementChoicesType, response: element.elementData.options.choices.reduce( - (acc, _, ix) => { - return { ...acc, [ix]: undefined } + (acc, choice) => { + return { ...acc, [choice.ix]: undefined } }, {} as Record ), diff --git a/packages/shared-components/src/questions/KPAnswerOptions.tsx b/packages/shared-components/src/questions/KPAnswerOptions.tsx index 78cb369887..5573746f76 100644 --- a/packages/shared-components/src/questions/KPAnswerOptions.tsx +++ b/packages/shared-components/src/questions/KPAnswerOptions.tsx @@ -11,7 +11,7 @@ import ChoiceFeedback from '../evaluation/ChoiceFeedback' export interface KPAnswerOptionsProps { displayMode?: ElementDisplayMode type: ElementType - choices: Partial[] + choices: Choice[] feedbacks?: QuestionFeedback[] | null value?: Record onChange: (newValue: Record) => void @@ -40,14 +40,14 @@ export function KPAnswerOptions({ : 'flex flex-col' )} > - {choices.map((choice, index) => ( -
+ {choices.map((choice) => ( +
onChange({ ...value, [index]: true })} + active={value?.[choice.ix] === true} + onClick={() => onChange({ ...value, [choice.ix]: true })} data={{ - cy: `toggle-kp-${elementIx + 1}-answer-${index + 1}-correct`, + cy: `toggle-kp-${elementIx + 1}-answer-${choice.ix + 1}-correct`, }} disabled={disabled} > @@ -85,11 +85,11 @@ export function KPAnswerOptions({ 'hover:bg-unset min-h-[2.5rem] border-slate-400' ), }} - active={value?.[index] === false} - onClick={() => onChange({ ...value, [index]: false })} + active={value?.[choice.ix] === false} + onClick={() => onChange({ ...value, [choice.ix]: false })} data={{ cy: `toggle-kp-${elementIx + 1}-answer-${ - index + 1 + choice.ix + 1 }-incorrect`, }} disabled={disabled} @@ -100,8 +100,8 @@ export function KPAnswerOptions({
- {!hideFeedbacks && feedbacks && feedbacks[index] && ( - + {!hideFeedbacks && feedbacks && feedbacks[choice.ix] && ( + )}
))} diff --git a/packages/shared-components/src/questions/MCAnswerOptions.tsx b/packages/shared-components/src/questions/MCAnswerOptions.tsx index f7a5ab5d71..24805c7186 100644 --- a/packages/shared-components/src/questions/MCAnswerOptions.tsx +++ b/packages/shared-components/src/questions/MCAnswerOptions.tsx @@ -9,7 +9,7 @@ import ChoiceFeedback from '../evaluation/ChoiceFeedback' export interface MCAnswerOptionsProps { displayMode?: ElementDisplayMode - choices: Partial[] + choices: Choice[] feedbacks?: QuestionFeedback[] | null value?: Record onChange: (value: Record) => void @@ -45,9 +45,9 @@ export function MCAnswerOptions({ b: (text) => {text}, })}
- {choices.map((choice, index) => { + {choices.map((choice) => { return ( -
+
- {!hideFeedbacks && feedbacks && feedbacks[index] && ( - + {!hideFeedbacks && feedbacks && feedbacks[choice.ix] && ( + )}
) diff --git a/packages/shared-components/src/questions/SCAnswerOptions.tsx b/packages/shared-components/src/questions/SCAnswerOptions.tsx index 5c0f13328b..b4ba9f6be1 100644 --- a/packages/shared-components/src/questions/SCAnswerOptions.tsx +++ b/packages/shared-components/src/questions/SCAnswerOptions.tsx @@ -9,7 +9,7 @@ import ChoiceFeedback from '../evaluation/ChoiceFeedback' export interface SCAnswerOptionsProps { displayMode?: ElementDisplayMode - choices: Partial[] + choices: Choice[] feedbacks?: QuestionFeedback[] | null value?: Record onChange: (value: Record) => void @@ -45,9 +45,9 @@ export function SCAnswerOptions({ b: (text) => {text}, })}
- {choices.map((choice, index) => { + {choices.map((choice) => { return ( -
+
- {!hideFeedbacks && feedbacks && feedbacks[index] && ( - + {!hideFeedbacks && feedbacks && feedbacks[choice.ix] && ( + )}
) diff --git a/packages/util/src/index.ts b/packages/util/src/index.ts index d87b4a2054..c486f4e1fb 100644 --- a/packages/util/src/index.ts +++ b/packages/util/src/index.ts @@ -5,6 +5,7 @@ import { } from '@klicker-uzh/prisma' import { type AllElementTypeData, + type Choice, type ElementInstanceResults, type ElementKeys, type ElementOptionsChoices, @@ -99,12 +100,10 @@ export function getInitialElementResults( element.type === PrismaElementType.MC || element.type === PrismaElementType.KPRIM ) { - const choices = (element.options as ElementOptionsChoices).choices.reduce< - Record - >( - (acc, _, ix: number) => ({ + const choices = element.options.choices.reduce( + (acc: Record, choice: Choice) => ({ ...acc, - [ix]: 0, + [choice.ix]: 0, }), {} ) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3f3bead032..17f3fdf874 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -641,6 +641,12 @@ importers: '@socialgouv/matomo-next': specifier: 1.9.1 version: 1.9.1(next@15.0.0(@opentelemetry/api@1.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) + '@tanstack/react-table': + specifier: 8.20.5 + version: 8.20.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@uidotdev/usehooks': + specifier: 2.4.1 + version: 2.4.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@uzh-bf/design-system': specifier: 3.0.0-alpha.32 version: 3.0.0-alpha.32(@fortawesome/fontawesome-svg-core@6.6.0)(@fortawesome/free-regular-svg-icons@6.6.0)(@fortawesome/free-solid-svg-icons@6.6.0)(@fortawesome/react-fontawesome@0.2.2(@fortawesome/fontawesome-svg-core@6.6.0)(react@18.3.1))(@types/react-dom@18.3.1)(@types/react@18.3.11)(class-variance-authority@0.7.0)(clsx@2.1.1)(dayjs@1.11.13)(formik@2.4.6(react@18.3.1))(lucide-react@0.424.0(react@18.3.1))(postcss-import@16.1.0(postcss@8.4.47))(postcss@8.4.47)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(tailwind-merge@2.5.4)(tailwindcss-animate@1.0.7(tailwindcss@3.4.14(ts-node@10.9.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(@types/node@20.16.1)(typescript@5.6.3))))(tailwindcss-radix@3.0.5(tailwindcss@3.4.14(ts-node@10.9.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(@types/node@20.16.1)(typescript@5.6.3))))(tailwindcss@3.4.14(ts-node@10.9.1(@swc/core@1.3.101(@swc/helpers@0.5.13))(@types/node@20.16.1)(typescript@5.6.3)))(yup@1.4.0) @@ -674,6 +680,9 @@ importers: lodash: specifier: 4.17.21 version: 4.17.21 + nanoid: + specifier: 5.0.8 + version: 5.0.8 next: specifier: 15.0.0 version: 15.0.0(@babel/core@7.25.8)(@opentelemetry/api@1.9.0)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -1050,107 +1059,6 @@ importers: specifier: ~5.6.3 version: 5.6.3 - apps/func-migration-v2-export: - dependencies: - '@azure/functions': - specifier: 4.5.1 - version: 4.5.1 - '@azure/storage-blob': - specifier: 12.25.0 - version: 12.25.0 - axios: - specifier: 1.7.7 - version: 1.7.7(debug@4.3.7) - jsonwebtoken: - specifier: 9.0.2 - version: 9.0.2 - mongodb: - specifier: 5.7.0 - version: 5.7.0 - devDependencies: - '@types/jsonwebtoken': - specifier: ^9.0.7 - version: 9.0.7 - '@types/node': - specifier: ^20.16.1 - version: 20.16.1 - azure-functions-core-tools: - specifier: ~4.0.6280 - version: 4.0.6280 - cross-env: - specifier: ~7.0.3 - version: 7.0.3 - eslint: - specifier: ~8.45.0 - version: 8.45.0 - npm-run-all: - specifier: ~4.1.5 - version: 4.1.5 - tsup: - specifier: ~8.3.0 - version: 8.3.0(@swc/core@1.3.101(@swc/helpers@0.5.13))(jiti@1.21.6)(postcss@8.4.47)(tsx@4.19.1)(typescript@5.6.3)(yaml@2.6.0) - typescript: - specifier: ~5.6.3 - version: 5.6.3 - - apps/func-migration-v3-import: - dependencies: - '@azure/functions': - specifier: 4.5.1 - version: 4.5.1 - '@azure/storage-blob': - specifier: 12.25.0 - version: 12.25.0 - '@klicker-uzh/prisma': - specifier: workspace:* - version: link:../../packages/prisma - axios: - specifier: 1.7.7 - version: 1.7.7(debug@4.3.7) - jsonwebtoken: - specifier: 9.0.2 - version: 9.0.2 - mongoose: - specifier: 7.3.3 - version: 7.3.3 - uuid: - specifier: 10.0.0 - version: 10.0.0 - devDependencies: - '@types/jsonwebtoken': - specifier: ^9.0.7 - version: 9.0.7 - '@types/node': - specifier: ^20.16.1 - version: 20.16.1 - '@types/uuid': - specifier: ^10.0.0 - version: 10.0.0 - azure-functions-core-tools: - specifier: ~4.0.6280 - version: 4.0.6280 - cross-env: - specifier: ~7.0.3 - version: 7.0.3 - eslint: - specifier: ~8.45.0 - version: 8.45.0 - npm-run-all: - specifier: ~4.1.5 - version: 4.1.5 - prisma: - specifier: ~5.21.0 - version: 5.21.0 - tsup: - specifier: ~8.3.0 - version: 8.3.0(@swc/core@1.3.101(@swc/helpers@0.5.13))(jiti@1.21.6)(postcss@8.4.47)(tsx@4.19.1)(typescript@5.6.3)(yaml@2.6.0) - tsx: - specifier: ~4.19.1 - version: 4.19.1 - typescript: - specifier: ~5.6.3 - version: 5.6.3 - apps/func-response-processor: dependencies: '@azure/functions': @@ -1523,9 +1431,6 @@ importers: mathjs: specifier: 11.9.1 version: 11.9.1 - mongodb: - specifier: 5.7.0 - version: 5.7.0 node-schedule: specifier: 2.1.1 version: 2.1.1 @@ -12267,42 +12172,6 @@ packages: mongodb-connection-string-url@2.6.0: resolution: {integrity: sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==} - mongodb@5.6.0: - resolution: {integrity: sha512-z8qVs9NfobHJm6uzK56XBZF8XwM9H294iRnB7wNjF0SnY93si5HPziIJn+qqvUR5QOff/4L0gCD6SShdR/GtVQ==} - engines: {node: '>=14.20.1'} - peerDependencies: - '@aws-sdk/credential-providers': ^3.201.0 - mongodb-client-encryption: '>=2.3.0 <3' - snappy: ^7.2.2 - peerDependenciesMeta: - '@aws-sdk/credential-providers': - optional: true - mongodb-client-encryption: - optional: true - snappy: - optional: true - - mongodb@5.7.0: - resolution: {integrity: sha512-zm82Bq33QbqtxDf58fLWBwTjARK3NSvKYjyz997KSy6hpat0prjeX/kxjbPVyZY60XYPDNETaHkHJI2UCzSLuw==} - engines: {node: '>=14.20.1'} - peerDependencies: - '@aws-sdk/credential-providers': ^3.201.0 - '@mongodb-js/zstd': ^1.1.0 - kerberos: ^2.0.1 - mongodb-client-encryption: '>=2.3.0 <3' - snappy: ^7.2.2 - peerDependenciesMeta: - '@aws-sdk/credential-providers': - optional: true - '@mongodb-js/zstd': - optional: true - kerberos: - optional: true - mongodb-client-encryption: - optional: true - snappy: - optional: true - mongodb@5.9.2: resolution: {integrity: sha512-H60HecKO4Bc+7dhOv4sJlgvenK4fQNqqUIlXxZYQNbfEWSALGAwGoyJd/0Qwk4TttFXUOHJ2ZJQe/52ScaUwtQ==} engines: {node: '>=14.20.1'} @@ -12324,10 +12193,6 @@ packages: snappy: optional: true - mongoose@7.3.3: - resolution: {integrity: sha512-g4NrRGIUEUYLeScaSChQR8i4Dlk9lR0UJzkK3r6TPJyqJ6ZWdRVP3oXfOG9Yn+hNeKcCJKfVEHo+jsU1rh3YTA==} - engines: {node: '>=14.20.1'} - mongoose@7.8.1: resolution: {integrity: sha512-c3MY8P1mGUGO+0H8rqxMNmAmhP0xb2EPNItfr7tHAHkh52uB0owH4Gu6q1GTUYj8yoHEDG5MN2V1aBBR6aJPuA==} engines: {node: '>=14.20.1'} @@ -12393,6 +12258,11 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanoid@5.0.8: + resolution: {integrity: sha512-TcJPw+9RV9dibz1hHUzlLVy8N4X9TnwirAjrU08Juo6BNKggzVfP2ZJ/3ZUSq15Xl5i85i+Z89XBO90pB2PghQ==} + engines: {node: ^18 || >=20} + hasBin: true + napi-build-utils@1.0.2: resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} @@ -13725,7 +13595,6 @@ packages: engines: {node: '>=0.6.0', teleport: '>=0.2.0'} deprecated: |- You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other. - (For a CapTP with native promises, see @endo/eventual-send and @endo/captp) qrcode-generator@1.4.4: @@ -14461,10 +14330,6 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - saslprep@1.0.3: - resolution: {integrity: sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==} - engines: {node: '>=6'} - sax@1.1.4: resolution: {integrity: sha512-5f3k2PbGGp+YtKJjOItpg3P99IMD84E4HOvcfleTb5joCHNXYLsR9yWFPOYGgaeMPDubQILTCMdsFb2OMeOjtg==} @@ -16201,6 +16066,7 @@ packages: workbox-google-analytics@6.5.4: resolution: {integrity: sha512-8AU1WuaXsD49249Wq0B2zn4a/vvFfHkpcFfqAFHNHwln3jK9QUYmzdkKXGIZl9wyKNP+RRX30vcgcyWMcZ9VAg==} + deprecated: It is not compatible with newer versions of GA starting with v4, as long as you are using GAv3 it should be ok, but the package is not longer being maintained workbox-navigation-preload@6.5.4: resolution: {integrity: sha512-IIwf80eO3cr8h6XSQJF+Hxj26rg2RPFVUmJLUlM0+A2GzB4HFbQyKkrgD5y2d84g2IbJzP4B4j5dPBRzamHrng==} @@ -27733,8 +27599,8 @@ snapshots: '@typescript-eslint/parser': 6.21.0(eslint@8.45.0)(typescript@5.6.3) eslint: 8.45.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.45.0) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.45.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint@8.45.0))(eslint@8.45.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint@8.45.0))(eslint@8.45.0))(eslint@8.45.0) eslint-plugin-jsx-a11y: 6.10.1(eslint@8.45.0) eslint-plugin-react: 7.35.0(eslint@8.45.0) eslint-plugin-react-hooks: 5.0.0(eslint@8.45.0) @@ -27760,13 +27626,13 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.45.0): + eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint@8.45.0))(eslint@8.45.0): dependencies: debug: 4.3.7(supports-color@5.5.0) enhanced-resolve: 5.17.1 eslint: 8.45.0 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.45.0))(eslint@8.45.0) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.45.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint@8.45.0))(eslint@8.45.0))(eslint@8.45.0) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint@8.45.0))(eslint@8.45.0))(eslint@8.45.0) fast-glob: 3.3.2 get-tsconfig: 4.7.6 is-core-module: 2.15.1 @@ -27777,18 +27643,18 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.45.0))(eslint@8.45.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint@8.45.0))(eslint@8.45.0))(eslint@8.45.0): dependencies: debug: 3.2.7(supports-color@8.1.1) optionalDependencies: '@typescript-eslint/parser': 6.21.0(eslint@8.45.0)(typescript@5.6.3) eslint: 8.45.0 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.45.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint@8.45.0))(eslint@8.45.0) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.45.0): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint@8.45.0))(eslint@8.45.0))(eslint@8.45.0): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -27799,7 +27665,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.45.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.45.0))(eslint@8.45.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.45.0)(typescript@5.6.3))(eslint@8.45.0))(eslint@8.45.0))(eslint@8.45.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -31649,22 +31515,6 @@ snapshots: '@types/whatwg-url': 8.2.2 whatwg-url: 11.0.0 - mongodb@5.6.0: - dependencies: - bson: 5.5.1 - mongodb-connection-string-url: 2.6.0 - socks: 2.8.3 - optionalDependencies: - saslprep: 1.0.3 - - mongodb@5.7.0: - dependencies: - bson: 5.5.1 - mongodb-connection-string-url: 2.6.0 - socks: 2.8.3 - optionalDependencies: - saslprep: 1.0.3 - mongodb@5.9.2: dependencies: bson: 5.5.1 @@ -31673,21 +31523,6 @@ snapshots: optionalDependencies: '@mongodb-js/saslprep': 1.1.8 - mongoose@7.3.3: - dependencies: - bson: 5.5.1 - kareem: 2.5.1 - mongodb: 5.6.0 - mpath: 0.9.0 - mquery: 5.0.0 - ms: 2.1.3 - sift: 16.0.1 - transitivePeerDependencies: - - '@aws-sdk/credential-providers' - - mongodb-client-encryption - - snappy - - supports-color - mongoose@7.8.1: dependencies: bson: 5.5.1 @@ -31761,6 +31596,8 @@ snapshots: nanoid@3.3.7: {} + nanoid@5.0.8: {} + napi-build-utils@1.0.2: {} native-duplexpair@1.0.0: {} @@ -34220,11 +34057,6 @@ snapshots: safer-buffer@2.1.2: {} - saslprep@1.0.3: - dependencies: - sparse-bitfield: 3.0.3 - optional: true - sax@1.1.4: {} sax@1.4.1: {} diff --git a/turbo.json b/turbo.json index 4adb29892a..63869d3186 100644 --- a/turbo.json +++ b/turbo.json @@ -30,12 +30,6 @@ "FUNCTIONS_EXTENSION_VERSION", "FUNCTIONS_WORKER_PROCESS_COUNT", "FUNCTIONS_WORKER_RUNTIME", - "LISTMONK_PASS", - "LISTMONK_TEMPLATE_MIGRATION_FAILURE", - "LISTMONK_TEMPLATE_MIGRATION_REQUEST", - "LISTMONK_TEMPLATE_MIGRATION_SUCCESS", - "LISTMONK_URL", - "LISTMONK_USER", "LTI_DB_TYPE", "LTI_DB_HOST", "LTI_DB_PORT", @@ -121,23 +115,11 @@ ], "persistent": true }, - "dev:migration": { - "cache": false, - "dependsOn": [ - "@klicker-uzh/util#build", - "@klicker-uzh/prisma#build", - "@klicker-uzh/graphql#build", - "@klicker-uzh/markdown#build", - "@klicker-uzh/transactional#build" - ], - "persistent": true - }, "dev:docs": { "cache": false, "persistent": true }, "dev:test": { - "dependsOn": ["^build:test", "build:test"], "outputs": ["dist/**", ".next/**", "build/**", "out/**"], "persistent": true }, @@ -156,6 +138,10 @@ "test": { "cache": false }, + "test:watch": { + "cache": false, + "persistent": true + }, "test:run": { "cache": false } diff --git a/util/listmonk-config.toml b/util/listmonk-config.toml deleted file mode 100644 index a5e7e00868..0000000000 --- a/util/listmonk-config.toml +++ /dev/null @@ -1,31 +0,0 @@ -[app] -# Interface and port where the app will run its webserver. The default value -# of localhost will only listen to connections from the current machine. To -# listen on all interfaces use '0.0.0.0'. To listen on the default web address -# port, use port 80 (this will require running with elevated permissions). -address = "0.0.0.0:9000" - -# BasicAuth authentication for the admin dashboard. This will eventually -# be replaced with a better multi-user, role-based authentication system. -# IMPORTANT: Leave both values empty to disable authentication on admin -# only where an external authentication is already setup. -admin_username = "listmonk" -admin_password = "listmonk" - -# Database. -[db] -host = "listmonk_db" -port = 5432 -user = "listmonk" -password = "listmonk" - -# Ensure that this database has been created in Postgres. -database = "listmonk" - -ssl_mode = "disable" -max_open = 25 -max_idle = 25 -max_lifetime = "300s" - -# Optional space separated Postgres DSN params. eg: "application_name=listmonk gssencmode=disable" -params = ""