From 1a80605850a26d84a44d274ae102ff2654e712c4 Mon Sep 17 00:00:00 2001 From: Kiran Kharade Date: Sat, 22 Apr 2023 10:36:09 +0530 Subject: [PATCH 01/66] Fixed npm audit errors --- package-lock.json | 128 ++++++++++++++-------------------------------- 1 file changed, 39 insertions(+), 89 deletions(-) diff --git a/package-lock.json b/package-lock.json index eeeff41..5c76ec9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2077,7 +2077,8 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "node_modules/array-flatten": { "version": "1.1.1", @@ -2173,9 +2174,9 @@ } }, "node_modules/aws-sdk": { - "version": "2.1295.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1295.0.tgz", - "integrity": "sha512-HVYoFCyfiL8gzL/c0lSRTg8tWBLfqAEDfwzGe338ww/LahpmC6C07S71SBBIvtGq3dpd7IwEobAbubZDijrA0Q==", + "version": "2.1363.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1363.0.tgz", + "integrity": "sha512-M2MZZXehgi/EMQv5GlzRkn3TlhoOYHg2cYdSAAqhjv67WaEG50MjaQy5vRvfN1i8XvB24aJFJ5pCrx69TaCaIg==", "dependencies": { "buffer": "4.9.2", "events": "1.1.1", @@ -2186,7 +2187,7 @@ "url": "0.10.3", "util": "^0.12.4", "uuid": "8.0.0", - "xml2js": "0.4.19" + "xml2js": "0.5.0" }, "engines": { "node": ">= 10.0.0" @@ -2994,18 +2995,6 @@ "node": ">= 8" } }, - "node_modules/date-fns": { - "version": "2.29.3", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", - "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", - "engines": { - "node": ">=0.11" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" - } - }, "node_modules/dateformat": { "version": "4.6.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", @@ -5687,6 +5676,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -8567,26 +8557,23 @@ } }, "node_modules/typeorm": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.12.tgz", - "integrity": "sha512-sYSxBmCf1nJLLTcYtwqZ+lQIRtLPyUoO93rHTOKk9vJCyT4UfRtU7oRsJvfvKP3nnZTD1hzz2SEy2zwPEN6OyA==", + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.15.tgz", + "integrity": "sha512-R4JSw8QjDP1W+ypeRz/XrCXIqubrLSnNAzJAp9EQSQIPHTv+YmUHZis8g08lOwFpuhqL9m8jkPSz8GWEKlU/ow==", "dependencies": { "@sqltools/formatter": "^1.2.5", "app-root-path": "^3.1.0", "buffer": "^6.0.3", "chalk": "^4.1.2", "cli-highlight": "^2.1.11", - "date-fns": "^2.29.3", "debug": "^4.3.4", "dotenv": "^16.0.3", "glob": "^8.1.0", - "js-yaml": "^4.1.0", "mkdirp": "^2.1.3", "reflect-metadata": "^0.1.13", "sha.js": "^2.4.11", "tslib": "^2.5.0", "uuid": "^9.0.0", - "xml2js": "^0.4.23", "yargs": "^17.6.2" }, "bin": { @@ -8606,8 +8593,8 @@ "better-sqlite3": "^7.1.2 || ^8.0.0", "hdb-pool": "^0.1.6", "ioredis": "^5.0.4", - "mongodb": "^3.6.0", - "mssql": "^7.3.0", + "mongodb": "^5.2.0", + "mssql": "^9.1.1", "mysql2": "^2.2.5 || ^3.0.1", "oracledb": "^5.1.0", "pg": "^8.5.1", @@ -8720,26 +8707,6 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" }, - "node_modules/typeorm/node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/typeorm/node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "engines": { - "node": ">=4.0" - } - }, "node_modules/typescript": { "version": "4.9.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", @@ -9123,18 +9090,21 @@ } }, "node_modules/xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", "dependencies": { "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" } }, "node_modules/xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ==", + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", "engines": { "node": ">=4.0" } @@ -10769,7 +10739,8 @@ "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "array-flatten": { "version": "1.1.1", @@ -10835,9 +10806,9 @@ "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" }, "aws-sdk": { - "version": "2.1295.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1295.0.tgz", - "integrity": "sha512-HVYoFCyfiL8gzL/c0lSRTg8tWBLfqAEDfwzGe338ww/LahpmC6C07S71SBBIvtGq3dpd7IwEobAbubZDijrA0Q==", + "version": "2.1363.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1363.0.tgz", + "integrity": "sha512-M2MZZXehgi/EMQv5GlzRkn3TlhoOYHg2cYdSAAqhjv67WaEG50MjaQy5vRvfN1i8XvB24aJFJ5pCrx69TaCaIg==", "requires": { "buffer": "4.9.2", "events": "1.1.1", @@ -10848,7 +10819,7 @@ "url": "0.10.3", "util": "^0.12.4", "uuid": "8.0.0", - "xml2js": "0.4.19" + "xml2js": "0.5.0" }, "dependencies": { "uuid": { @@ -11452,11 +11423,6 @@ "which": "^2.0.1" } }, - "date-fns": { - "version": "2.29.3", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", - "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==" - }, "dateformat": { "version": "4.6.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", @@ -13478,6 +13444,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "requires": { "argparse": "^2.0.1" } @@ -15577,26 +15544,23 @@ } }, "typeorm": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.12.tgz", - "integrity": "sha512-sYSxBmCf1nJLLTcYtwqZ+lQIRtLPyUoO93rHTOKk9vJCyT4UfRtU7oRsJvfvKP3nnZTD1hzz2SEy2zwPEN6OyA==", + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.15.tgz", + "integrity": "sha512-R4JSw8QjDP1W+ypeRz/XrCXIqubrLSnNAzJAp9EQSQIPHTv+YmUHZis8g08lOwFpuhqL9m8jkPSz8GWEKlU/ow==", "requires": { "@sqltools/formatter": "^1.2.5", "app-root-path": "^3.1.0", "buffer": "^6.0.3", "chalk": "^4.1.2", "cli-highlight": "^2.1.11", - "date-fns": "^2.29.3", "debug": "^4.3.4", "dotenv": "^16.0.3", "glob": "^8.1.0", - "js-yaml": "^4.1.0", "mkdirp": "^2.1.3", "reflect-metadata": "^0.1.13", "sha.js": "^2.4.11", "tslib": "^2.5.0", "uuid": "^9.0.0", - "xml2js": "^0.4.23", "yargs": "^17.6.2" }, "dependencies": { @@ -15618,20 +15582,6 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==" - }, - "xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - } - }, - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" } } }, @@ -15923,18 +15873,18 @@ } }, "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", "requires": { "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" + "xmlbuilder": "~11.0.0" } }, "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ==" + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" }, "xtend": { "version": "4.0.2", From 0ff9189d5d5be4fc249bda91468bf54c1678f21a Mon Sep 17 00:00:00 2001 From: Kiran Kharade Date: Tue, 25 Apr 2023 12:44:35 +0530 Subject: [PATCH 02/66] Updated entrypoint.sh --- entrypoint.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index b6d4e4c..94fa6f5 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -2,12 +2,8 @@ # Add config/creds copying here.. aws s3 cp s3://$S3_CONFIG_BUCKET/$S3_CONFIG_PATH/env.config /app/.env -aws s3 cp s3://$S3_CONFIG_BUCKET/$S3_CONFIG_PATH/careplan.config.json /app/careplan.config.json aws s3 cp s3://$S3_CONFIG_BUCKET/$S3_CONFIG_PATH/seed_data/internal.clients.seed.json /app/seed.data/internal.clients.seed.json aws s3 cp s3://$S3_CONFIG_BUCKET/$S3_CONFIG_PATH/seed_data/default.users.seed.json /app/seed.data/default.users.seed.json -# aws s3 cp s3://$S3_CONFIG_BUCKET/$S3_CONFIG_PATH/seed_data/system.admin.seed.json /app/seed.data/system.admin.seed.json -# aws s3 cp s3://$S3_CONFIG_BUCKET/$S3_CONFIG_PATH/gcp_creds/reancareapi-307085d27fd7.json /app/creds/reancareapi-307085d27fd7.json -# aws s3 cp s3://$S3_CONFIG_BUCKET/$S3_CONFIG_PATH/gcp_creds/reancare_firebase_creds.json /app/creds/reancare_firebase_creds.json cd /app # Add any other scripts here... From 651f14b739813954bdcf26d09052448dfffed001 Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 26 Apr 2023 02:01:13 +0530 Subject: [PATCH 03/66] Create dev-ci-cd.yml --- .github/workflows/dev-ci-cd.yml | 118 ++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 .github/workflows/dev-ci-cd.yml diff --git a/.github/workflows/dev-ci-cd.yml b/.github/workflows/dev-ci-cd.yml new file mode 100644 index 0000000..c33212c --- /dev/null +++ b/.github/workflows/dev-ci-cd.yml @@ -0,0 +1,118 @@ +# This workflow will trigger pull requests and apply a label based on the +# paths that are modified in the pull request. +# +# To use this workflow, you will need to set up a .github/labeler.yml +# file with configuration. For more information, see: +# https://github.com/actions/labeler + + +name: Dev-CI-CD + +## Controls when the workflow will run +on: + # Triggers the workflow on push events but only for the develop branch + push: + branches: [develop] + +jobs: + Deploy-ECS: + environment: dev + runs-on: ubuntu-latest +# group: Default Larger Runners +# labels: ubuntu-latest-4-cores + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Declare some variables + id: vars + shell: bash + run: | + echo "branch=$(echo ${GITHUB_REF#refs/heads/} | sed "s/\\//-/g")" >> $GITHUB_OUTPUT + echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT + echo "repo_name=$(echo "$GITHUB_REPOSITORY" | awk -F / '{print $2}')" >> $GITHUB_OUTPUT + + - name: Another step + run: | + echo "Branch: ${{ steps.vars.outputs.branch }}" + echo "Sha: ${{ steps.vars.outputs.sha_short }}" + echo "Repo: ${{ steps.vars.outputs.repo_name }}" + + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v1 + + - name: Cache Docker layers + uses: actions/cache@v3 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Build and push + id: docker_build + uses: docker/build-push-action@v3 + with: + context: ./ + file: ./Dockerfile + builder: ${{ steps.buildx.outputs.name }} + push: true + tags: ${{ steps.login-ecr.outputs.registry }}/awards-service:${{ steps.vars.outputs.branch }}_${{ steps.vars.outputs.sha_short }} + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache + env: + # 7 GiB by default on GitHub, setting this to 16 GiB + NODE_OPTIONS: "--max_old_space_size=8192" + + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} + + - name: Download task definition + run: | + aws ecs describe-task-definition --task-definition ${{ secrets.TASK_DEFINTION_NAME }} \ + --query taskDefinition > task-definition.json + + - name: New image ID in the Amazon ECS task definition + id: task-def + uses: aws-actions/amazon-ecs-render-task-definition@v1 + with: + task-definition: task-definition.json + container-name: default + image: ${{ steps.login-ecr.outputs.registry }}/reancare-service-dev-uat:${{ steps.vars.outputs.branch }}_${{ steps.vars.outputs.sha_short }} + + - name: Deploy Amazon ECS task definition + uses: aws-actions/amazon-ecs-deploy-task-definition@v1 + with: + task-definition: ${{ steps.task-def.outputs.task-definition }} + wait-for-service-stability: true + + - name: Task Definition Variable + id: taskdefintionvar + shell: bash + run: | + echo "task_definition_arn=$(aws ecs describe-task-definition --task-definition ${{ secrets.TASK_DEFINTION_NAME }} | jq '.[] | .taskDefinitionArn')" >> $GITHUB_OUTPUT + + - name: Task Defintion ARN + run: | + echo "Task Defintion: ${{ steps.taskdefintionvar.outputs.task_definition_arn }}" + + - name: Deploy Amazon ECS task definition using Duplo API + uses: fjogeleit/http-request-action@master + with: + url: 'https://reanfoundation.duplocloud.net/subscriptions/${{ secrets.DUPLO_ID }}/UpdateEcsService' + method: 'POST' + data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "${{ secrets.SERVICE_NAME }}","Replicas":1, "HealthCheckGracePeriodSeconds": 1200}' + bearerToken: ${{ secrets.DUPLOCLOUD_TOKEN }} From ee9b76fcc77fa612d85d97fa5f3922aa6d0c6bfd Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 26 Apr 2023 02:14:36 +0530 Subject: [PATCH 04/66] Update dev-ci-cd.yml --- .github/workflows/dev-ci-cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dev-ci-cd.yml b/.github/workflows/dev-ci-cd.yml index c33212c..62ebe26 100644 --- a/.github/workflows/dev-ci-cd.yml +++ b/.github/workflows/dev-ci-cd.yml @@ -114,5 +114,5 @@ jobs: with: url: 'https://reanfoundation.duplocloud.net/subscriptions/${{ secrets.DUPLO_ID }}/UpdateEcsService' method: 'POST' - data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "${{ secrets.SERVICE_NAME }}","Replicas":1, "HealthCheckGracePeriodSeconds": 1200}' + data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "${{ secrets.SERVICE_NAME }}","Replicas":0, "HealthCheckGracePeriodSeconds": 1200}' bearerToken: ${{ secrets.DUPLOCLOUD_TOKEN }} From 87e80508d10b12ed1fd00e4cfb3a49ebb0402e9f Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 26 Apr 2023 14:02:56 +0530 Subject: [PATCH 05/66] Update dev-ci-cd.yml --- .github/workflows/dev-ci-cd.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dev-ci-cd.yml b/.github/workflows/dev-ci-cd.yml index 62ebe26..1a50fc2 100644 --- a/.github/workflows/dev-ci-cd.yml +++ b/.github/workflows/dev-ci-cd.yml @@ -2,7 +2,7 @@ # paths that are modified in the pull request. # # To use this workflow, you will need to set up a .github/labeler.yml -# file with configuration. For more information, see: +# file with configuration. For more information, see : # https://github.com/actions/labeler @@ -108,6 +108,11 @@ jobs: - name: Task Defintion ARN run: | echo "Task Defintion: ${{ steps.taskdefintionvar.outputs.task_definition_arn }}" + + - name: print data + run: | + echo ID: ${{ secrets.DUPLO_ID }} + echo service_name: ${{ secrets.SERVICE_NAME }} - name: Deploy Amazon ECS task definition using Duplo API uses: fjogeleit/http-request-action@master @@ -116,3 +121,4 @@ jobs: method: 'POST' data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "${{ secrets.SERVICE_NAME }}","Replicas":0, "HealthCheckGracePeriodSeconds": 1200}' bearerToken: ${{ secrets.DUPLOCLOUD_TOKEN }} + From ffca47c20483144eb9770c12106cbf28854a93da Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 26 Apr 2023 14:07:35 +0530 Subject: [PATCH 06/66] Update dev-ci-cd.yml --- .github/workflows/dev-ci-cd.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/dev-ci-cd.yml b/.github/workflows/dev-ci-cd.yml index 1a50fc2..378a887 100644 --- a/.github/workflows/dev-ci-cd.yml +++ b/.github/workflows/dev-ci-cd.yml @@ -108,17 +108,13 @@ jobs: - name: Task Defintion ARN run: | echo "Task Defintion: ${{ steps.taskdefintionvar.outputs.task_definition_arn }}" - - - name: print data - run: | - echo ID: ${{ secrets.DUPLO_ID }} - echo service_name: ${{ secrets.SERVICE_NAME }} + - name: Deploy Amazon ECS task definition using Duplo API uses: fjogeleit/http-request-action@master with: url: 'https://reanfoundation.duplocloud.net/subscriptions/${{ secrets.DUPLO_ID }}/UpdateEcsService' method: 'POST' - data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "${{ secrets.SERVICE_NAME }}","Replicas":0, "HealthCheckGracePeriodSeconds": 1200}' + data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "duploservices-dev-awards-service","Replicas":0, "HealthCheckGracePeriodSeconds": 1200}' bearerToken: ${{ secrets.DUPLOCLOUD_TOKEN }} From 80deb7ea4aca686ef55810b9406e5a8af36047b9 Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 26 Apr 2023 14:18:57 +0530 Subject: [PATCH 07/66] Update dev-ci-cd.yml --- .github/workflows/dev-ci-cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dev-ci-cd.yml b/.github/workflows/dev-ci-cd.yml index 378a887..b43f4fa 100644 --- a/.github/workflows/dev-ci-cd.yml +++ b/.github/workflows/dev-ci-cd.yml @@ -115,6 +115,6 @@ jobs: with: url: 'https://reanfoundation.duplocloud.net/subscriptions/${{ secrets.DUPLO_ID }}/UpdateEcsService' method: 'POST' - data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "duploservices-dev-awards-service","Replicas":0, "HealthCheckGracePeriodSeconds": 1200}' + data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "${{ secrets.SERVICE_NAME }}","Replicas":1, "HealthCheckGracePeriodSeconds": 1200}' bearerToken: ${{ secrets.DUPLOCLOUD_TOKEN }} From 9433e5a122f18465af5b2b1334889640bc63ad5a Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 26 Apr 2023 14:23:26 +0530 Subject: [PATCH 08/66] Update dev-ci-cd.yml --- .github/workflows/dev-ci-cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dev-ci-cd.yml b/.github/workflows/dev-ci-cd.yml index b43f4fa..85a1758 100644 --- a/.github/workflows/dev-ci-cd.yml +++ b/.github/workflows/dev-ci-cd.yml @@ -115,6 +115,6 @@ jobs: with: url: 'https://reanfoundation.duplocloud.net/subscriptions/${{ secrets.DUPLO_ID }}/UpdateEcsService' method: 'POST' - data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "${{ secrets.SERVICE_NAME }}","Replicas":1, "HealthCheckGracePeriodSeconds": 1200}' + data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "awards-service","Replicas":1, "HealthCheckGracePeriodSeconds": 1200}' bearerToken: ${{ secrets.DUPLOCLOUD_TOKEN }} From cf8995c479a4c01c1a3e85958a03a238271df108 Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 26 Apr 2023 14:35:31 +0530 Subject: [PATCH 09/66] Update dev-ci-cd.yml --- .github/workflows/dev-ci-cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dev-ci-cd.yml b/.github/workflows/dev-ci-cd.yml index 85a1758..63e469b 100644 --- a/.github/workflows/dev-ci-cd.yml +++ b/.github/workflows/dev-ci-cd.yml @@ -115,6 +115,6 @@ jobs: with: url: 'https://reanfoundation.duplocloud.net/subscriptions/${{ secrets.DUPLO_ID }}/UpdateEcsService' method: 'POST' - data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "awards-service","Replicas":1, "HealthCheckGracePeriodSeconds": 1200}' + data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "awards","Replicas":0, "HealthCheckGracePeriodSeconds": 1200}' bearerToken: ${{ secrets.DUPLOCLOUD_TOKEN }} From cc8b356398e26bda72985f5555ddaf4246a39c07 Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 26 Apr 2023 14:37:41 +0530 Subject: [PATCH 10/66] Update dev-ci-cd.yml --- .github/workflows/dev-ci-cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dev-ci-cd.yml b/.github/workflows/dev-ci-cd.yml index 63e469b..ecba479 100644 --- a/.github/workflows/dev-ci-cd.yml +++ b/.github/workflows/dev-ci-cd.yml @@ -91,7 +91,7 @@ jobs: with: task-definition: task-definition.json container-name: default - image: ${{ steps.login-ecr.outputs.registry }}/reancare-service-dev-uat:${{ steps.vars.outputs.branch }}_${{ steps.vars.outputs.sha_short }} + image: ${{ steps.login-ecr.outputs.registry }}/awards-service:${{ steps.vars.outputs.branch }}_${{ steps.vars.outputs.sha_short }} - name: Deploy Amazon ECS task definition uses: aws-actions/amazon-ecs-deploy-task-definition@v1 From 5ba423593bab885a6163072331b26d8a59888ba1 Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 26 Apr 2023 14:47:52 +0530 Subject: [PATCH 11/66] Update dev-ci-cd.yml --- .github/workflows/dev-ci-cd.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/dev-ci-cd.yml b/.github/workflows/dev-ci-cd.yml index ecba479..afee6e8 100644 --- a/.github/workflows/dev-ci-cd.yml +++ b/.github/workflows/dev-ci-cd.yml @@ -82,7 +82,7 @@ jobs: - name: Download task definition run: | - aws ecs describe-task-definition --task-definition ${{ secrets.TASK_DEFINTION_NAME }} \ + aws ecs describe-task-definition --task-definition duploservices-dev-awards-service \ --query taskDefinition > task-definition.json - name: New image ID in the Amazon ECS task definition @@ -103,18 +103,18 @@ jobs: id: taskdefintionvar shell: bash run: | - echo "task_definition_arn=$(aws ecs describe-task-definition --task-definition ${{ secrets.TASK_DEFINTION_NAME }} | jq '.[] | .taskDefinitionArn')" >> $GITHUB_OUTPUT + echo "task_definition_arn=$(aws ecs describe-task-definition --task-definition duploservices-dev-awards-service | jq '.[] | .taskDefinitionArn')" >> $GITHUB_OUTPUT - name: Task Defintion ARN run: | echo "Task Defintion: ${{ steps.taskdefintionvar.outputs.task_definition_arn }}" - - name: Deploy Amazon ECS task definition using Duplo API - uses: fjogeleit/http-request-action@master - with: - url: 'https://reanfoundation.duplocloud.net/subscriptions/${{ secrets.DUPLO_ID }}/UpdateEcsService' - method: 'POST' - data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "awards","Replicas":0, "HealthCheckGracePeriodSeconds": 1200}' - bearerToken: ${{ secrets.DUPLOCLOUD_TOKEN }} + # - name: Deploy Amazon ECS task definition using Duplo API + # uses: fjogeleit/http-request-action@master + # with: + # url: 'https://reanfoundation.duplocloud.net/subscriptions/${{ secrets.DUPLO_ID }}/UpdateEcsService' + # method: 'POST' + # data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "awards","Replicas":0, "HealthCheckGracePeriodSeconds": 1200}' + # bearerToken: ${{ secrets.DUPLOCLOUD_TOKEN }} From de47cd4eece52992e8446f420e058cafcac581ed Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 26 Apr 2023 14:53:16 +0530 Subject: [PATCH 12/66] Update dev-ci-cd.yml --- .github/workflows/dev-ci-cd.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/dev-ci-cd.yml b/.github/workflows/dev-ci-cd.yml index afee6e8..41f60cd 100644 --- a/.github/workflows/dev-ci-cd.yml +++ b/.github/workflows/dev-ci-cd.yml @@ -110,11 +110,11 @@ jobs: echo "Task Defintion: ${{ steps.taskdefintionvar.outputs.task_definition_arn }}" - # - name: Deploy Amazon ECS task definition using Duplo API - # uses: fjogeleit/http-request-action@master - # with: - # url: 'https://reanfoundation.duplocloud.net/subscriptions/${{ secrets.DUPLO_ID }}/UpdateEcsService' - # method: 'POST' - # data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "awards","Replicas":0, "HealthCheckGracePeriodSeconds": 1200}' - # bearerToken: ${{ secrets.DUPLOCLOUD_TOKEN }} + - name: Deploy Amazon ECS task definition using Duplo API + uses: fjogeleit/http-request-action@master + with: + url: 'https://reanfoundation.duplocloud.net/subscriptions/${{ secrets.DUPLO_ID }}/UpdateEcsService' + method: 'POST' + data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "awards","Replicas":0, "HealthCheckGracePeriodSeconds": 1200}' + bearerToken: ${{ secrets.DUPLOCLOUD_TOKEN }} From 4e93fa3759be558869245c52fb2ca6a1f5fe2ddf Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 26 Apr 2023 14:57:13 +0530 Subject: [PATCH 13/66] Update dev-ci-cd.yml --- .github/workflows/dev-ci-cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dev-ci-cd.yml b/.github/workflows/dev-ci-cd.yml index 41f60cd..a370ee9 100644 --- a/.github/workflows/dev-ci-cd.yml +++ b/.github/workflows/dev-ci-cd.yml @@ -115,6 +115,6 @@ jobs: with: url: 'https://reanfoundation.duplocloud.net/subscriptions/${{ secrets.DUPLO_ID }}/UpdateEcsService' method: 'POST' - data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "awards","Replicas":0, "HealthCheckGracePeriodSeconds": 1200}' + data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "awards","Replicas":1, "HealthCheckGracePeriodSeconds": 1200, "DnsPrfx": ""}' bearerToken: ${{ secrets.DUPLOCLOUD_TOKEN }} From e3815eaf712aa994d4e1d38ab957ede2fb729335 Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 26 Apr 2023 15:02:43 +0530 Subject: [PATCH 14/66] Update dev-ci-cd.yml --- .github/workflows/dev-ci-cd.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dev-ci-cd.yml b/.github/workflows/dev-ci-cd.yml index a370ee9..191fa97 100644 --- a/.github/workflows/dev-ci-cd.yml +++ b/.github/workflows/dev-ci-cd.yml @@ -82,7 +82,7 @@ jobs: - name: Download task definition run: | - aws ecs describe-task-definition --task-definition duploservices-dev-awards-service \ + aws ecs describe-task-definition --task-definition ${{ secrets.TASK_DEFINTION_NAME }} \ --query taskDefinition > task-definition.json - name: New image ID in the Amazon ECS task definition @@ -103,7 +103,7 @@ jobs: id: taskdefintionvar shell: bash run: | - echo "task_definition_arn=$(aws ecs describe-task-definition --task-definition duploservices-dev-awards-service | jq '.[] | .taskDefinitionArn')" >> $GITHUB_OUTPUT + echo "task_definition_arn=$(aws ecs describe-task-definition --task-definition ${{ secrets.TASK_DEFINTION_NAME }} | jq '.[] | .taskDefinitionArn')" >> $GITHUB_OUTPUT - name: Task Defintion ARN run: | @@ -115,6 +115,6 @@ jobs: with: url: 'https://reanfoundation.duplocloud.net/subscriptions/${{ secrets.DUPLO_ID }}/UpdateEcsService' method: 'POST' - data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "awards","Replicas":1, "HealthCheckGracePeriodSeconds": 1200, "DnsPrfx": ""}' + data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "${{ secrets.SERVICE_NAME }}","Replicas":1, "HealthCheckGracePeriodSeconds": 1200, "DnsPrfx": ""}' bearerToken: ${{ secrets.DUPLOCLOUD_TOKEN }} From e9d1c6b1f0c1ae8b2dc835e6d8c2fc89026b4476 Mon Sep 17 00:00:00 2001 From: Kiran Kharade Date: Fri, 28 Apr 2023 10:46:55 +0530 Subject: [PATCH 15/66] Added a step to create facts database if it does not exist.l --- src/app.ts | 2 + .../fact.extractors/facts.db.client.ts | 64 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 src/modules/fact.extractors/facts.db.client.ts diff --git a/src/app.ts b/src/app.ts index 3c2a045..f2a9f71 100644 --- a/src/app.ts +++ b/src/app.ts @@ -13,6 +13,7 @@ import { Seeder } from './startup/seeder'; import { DBConnector } from "./database/database.connector"; import { FactsDBConnector } from "./modules/fact.extractors/facts.db.connector"; import { HttpLogger } from "./logger/HttpLogger"; +import FactsDbClient from "./modules/fact.extractors/facts.db.client"; ///////////////////////////////////////////////////////////////////////// @@ -65,6 +66,7 @@ export default class Application { await DbClient.createDatabase(); await DBConnector.initialize(); + await FactsDbClient.createDatabase(); await FactsDBConnector.initialize(); }; diff --git a/src/modules/fact.extractors/facts.db.client.ts b/src/modules/fact.extractors/facts.db.client.ts new file mode 100644 index 0000000..430847f --- /dev/null +++ b/src/modules/fact.extractors/facts.db.client.ts @@ -0,0 +1,64 @@ +// eslint-disable-next-line @typescript-eslint/no-var-requires +const mysql = require('mysql2'); +import { logger } from '../../logger/logger'; +import { Config } from '../../database/database.config'; + +//////////////////////////////////////////////////////////////// + +export default class FactsDbClient { + + public static createDatabase = async () => { + try { + const database = `awards_facts`; + const query = `CREATE DATABASE ${database}`; + await FactsDbClient.executeQuery(query); + logger.info(`Database ${database} created successfully!`); + } catch (error) { + logger.error(error.message); + } + }; + + private static executeQuery = (query): Promise => { + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + return new Promise((resolve, reject) => { + try { + const connection = mysql.createConnection({ + host : Config.host, + user : Config.username, + password : Config.password, + }); + + connection.connect(function (err) { + if (err) { + logger.error(err.message); + reject(err); + } + + //logger.log('Connected!'); + connection.query(query, function (err, result) { + if (err) { + logger.error(err.message); + + var str = (result !== undefined && result !== null) ? result.toString() : null; + if (str != null) { + logger.error(str); + } + else { + logger.error(`Query: ${query}`); + } + reject(err); + } + resolve(true); + }); + }); + + } + catch (error) { + logger.error(error.message); + } + }); + + }; + +} \ No newline at end of file From eb2e612c500d7d129d399bffdc5d89e41a3eb11b Mon Sep 17 00:00:00 2001 From: Kiran Kharade Date: Tue, 9 May 2023 18:46:48 +0530 Subject: [PATCH 16/66] Config-changes --- service.config.json | 4 ++-- service.config.local.json | 2 +- src/domain.types/engine/engine.types.ts | 1 + src/modules/engine.execution/schema.engine.ts | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/service.config.json b/service.config.json index cc07998..de6b73a 100644 --- a/service.config.json +++ b/service.config.json @@ -1,5 +1,5 @@ { - "SystemIdentifier": "REAN Careplan Service", + "SystemIdentifier": "Awards Service", "Auth" : { "Authentication": "Custom", "Authorization": "Custom" @@ -25,6 +25,6 @@ }, "MaxUploadFileSize": 104857600, "JwtExpiresIn": 2592000, - "Logger" : "Winston", + "Logger" : "Custom", "UseHTTPLogging" : true } diff --git a/service.config.local.json b/service.config.local.json index 98abc43..82ca812 100644 --- a/service.config.local.json +++ b/service.config.local.json @@ -1,5 +1,5 @@ { - "SystemIdentifier": "REAN HealthGuru", + "SystemIdentifier": "Awards Service", "Auth" : { "Authentication": "Custom", "Authorization": "Custom" diff --git a/src/domain.types/engine/engine.types.ts b/src/domain.types/engine/engine.types.ts index 07b92cc..fb56128 100644 --- a/src/domain.types/engine/engine.types.ts +++ b/src/domain.types/engine/engine.types.ts @@ -143,6 +143,7 @@ export const ConditionOperandDataTypeList: OperandDataType[] = [ OperandDataType.Boolean, OperandDataType.Text, OperandDataType.Array, + OperandDataType.Object, OperandDataType.Date, ]; diff --git a/src/modules/engine.execution/schema.engine.ts b/src/modules/engine.execution/schema.engine.ts index eabe3d0..83333b9 100644 --- a/src/modules/engine.execution/schema.engine.ts +++ b/src/modules/engine.execution/schema.engine.ts @@ -138,7 +138,7 @@ export class SchemaEngine { } const added = await processor.storeData(context.id, almanacObject.Data.ToBeAdded, action.InputParams, action.OutputParams); var removedData = null; - if (almanacObject.Data.ToBeRemoved) { + if (almanacObject.Data.ToBeRemoved.length > 0) { const removed = await processor.removeData(context.id, almanacObject.Data.ToBeRemoved, action.InputParams, action.OutputParams); removedData = removed?.Data; } From 7e21653a4d5cfc4f4aa0bd332f074f92b7274408 Mon Sep 17 00:00:00 2001 From: vinay-debug <84920398+vinay-debug@users.noreply.github.com> Date: Thu, 11 May 2023 12:32:57 +0530 Subject: [PATCH 17/66] Made prefix allownull in person model --- src/database/models/user/person.model.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/database/models/user/person.model.ts b/src/database/models/user/person.model.ts index 38ea5db..4f93b7e 100644 --- a/src/database/models/user/person.model.ts +++ b/src/database/models/user/person.model.ts @@ -21,7 +21,7 @@ export class Person { @Column({ type: 'varchar', length: 256, nullable: true }) ReferenceId : string; //This is id of the person in external system - @Column({ type: 'varchar', length: 256, nullable: false }) + @Column({ type: 'varchar', length: 256, nullable: true }) Prefix : string; @Column({ type: 'varchar', length: 256, nullable: false }) From c68d8a2519741b5a301c01aa08aad73fde764547 Mon Sep 17 00:00:00 2001 From: Kiran Kharade Date: Wed, 17 May 2023 15:20:19 +0530 Subject: [PATCH 18/66] participant badges classification response --- .../participant/participant.controller.ts | 85 ++++++++++++++++++- src/database/services/awards/badge.service.ts | 20 +++++ 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/src/api/awards/participant/participant.controller.ts b/src/api/awards/participant/participant.controller.ts index 8103ea0..7e830c3 100644 --- a/src/api/awards/participant/participant.controller.ts +++ b/src/api/awards/participant/participant.controller.ts @@ -4,8 +4,10 @@ import { ParticipantValidator } from './participant.validator'; import { BaseController } from '../../base.controller'; import { ParticipantService } from '../../../database/services/awards/participant.service'; import { ErrorHandler } from '../../../common/handlers/error.handler'; -import { ParticipantCreateModel, ParticipantSearchFilters, ParticipantUpdateModel } from '../../../domain.types/awards/participant.domain.types'; +import { ParticipantBadgeResponseDto, ParticipantCreateModel, ParticipantSearchFilters, ParticipantUpdateModel } from '../../../domain.types/awards/participant.domain.types'; import { uuid } from '../../../domain.types/miscellaneous/system.types'; +import { BadgeService } from '../../../database/services/awards/badge.service'; +import { BadgeResponseDto } from '../../../domain.types/awards/badge.domain.types'; /////////////////////////////////////////////////////////////////////////////////////// @@ -15,11 +17,14 @@ export class ParticipantController extends BaseController { _service: ParticipantService = null; + _badgeService: BadgeService = null; + _validator: ParticipantValidator = null; constructor() { super(); this._service = new ParticipantService(); + this._badgeService = new BadgeService(); this._validator = new ParticipantValidator(); } @@ -117,11 +122,87 @@ export class ParticipantController extends BaseController { try { await this.authorize('Participant.GetBadges', request, response, false); var id: uuid = await this._validator.validateParamAsUUID(request, 'id'); - const result = await this._service.getBadges(id); + const participantBadges = await this._service.getBadges(id); const message = 'Participant badges retrieved successfully!'; + + const participant = await this._service.getById(id); + if (participant === null) { + ErrorHandler.throwNotFoundError(`Participant with Id: ${id} does not exist!`); + } + const clientId = participant.Client?.id; + const allBadges = await this._badgeService.getByClientId(clientId); + const badges = this.classifyAllBadgesByCategory(allBadges); + const classified = this.classifyParticipantBadges(participantBadges, badges); + + const result = { + BadgesByCategory: classified, + BadgeList: participantBadges, + }; + ResponseHandler.success(request, response, message, 200, result); } catch (error) { ResponseHandler.handleError(request, response, error); } }; + + private classifyAllBadgesByCategory = (allBadges: BadgeResponseDto[]) => { + const badges = allBadges.reduce((acc, x) => { + if (!acc[x.Category?.Name]) { + acc[x.Category?.Name] = { + CategoryName: x.Category?.Name, + Badges: {}, + }; + } + acc[x.Category?.Name].Badges[x.Name] = { + BadgeName: x.Name, + Occurence: 0, + BadgeList: [], + }; + return acc; + }, {}); + return badges; + }; + + private classifyParticipantBadges = (participantBadges: ParticipantBadgeResponseDto[], badges: any) => { + + const badgesByCategoryName = participantBadges.reduce((acc, x) => { + if (!acc[x.Badge?.Category?.Name]) { + acc[x.Badge?.Category?.Name] = []; + } + acc[x.Badge?.Category?.Name].push(x); + return acc; + }, {}); + + for (const key in badgesByCategoryName) { + + const arr = badgesByCategoryName[key]; + const classfiedByBadgeName = arr.reduce((acc, x) => { + if (!acc[x.Badge?.Name]) { + acc[x.Badge?.Name] = []; + } + acc[x.Badge?.Name].push(x); + return acc; + }, {}); + + badges[key] = { + CategoryName: key, + Badges: {}, + }; + + for (const badgeName in classfiedByBadgeName) { + let bArr = classfiedByBadgeName[badgeName] as any[]; + bArr = bArr.sort((a, b) => { + return a.Badge.Name.localeCompare(b.Badge.Name); + }); + const occurence = bArr.length; + badges[key].Badges[badgeName] = { + BadgeName: badgeName, + Occurence: occurence, + BadgeList: bArr, + }; + } + } + return badges; + }; + } diff --git a/src/database/services/awards/badge.service.ts b/src/database/services/awards/badge.service.ts index a732e38..1742111 100644 --- a/src/database/services/awards/badge.service.ts +++ b/src/database/services/awards/badge.service.ts @@ -63,6 +63,26 @@ export class BadgeService extends BaseService { } }; + public getByClientId = async (clientId: uuid): Promise => { + try { + var badges = await this._badgeRepository.find({ + where : { + Client : { + id : clientId + } + }, + relations: { + Category: true, + Client : true + } + }); + return badges.map(x => BadgeMapper.toResponseDto(x)); + } catch (error) { + logger.error(error.message); + ErrorHandler.throwInternalServerError(error.message, 500); + } + } + public search = async (filters: BadgeSearchFilters) : Promise => { try { From e03e1472e467faca16bf90a4833bc104d3efd302 Mon Sep 17 00:00:00 2001 From: tabbasum-rean Date: Wed, 17 May 2023 19:42:54 +0530 Subject: [PATCH 19/66] Corrected Occurrence Spell --- src/api/awards/participant/participant.controller.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/awards/participant/participant.controller.ts b/src/api/awards/participant/participant.controller.ts index 7e830c3..e597d6d 100644 --- a/src/api/awards/participant/participant.controller.ts +++ b/src/api/awards/participant/participant.controller.ts @@ -155,7 +155,7 @@ export class ParticipantController extends BaseController { } acc[x.Category?.Name].Badges[x.Name] = { BadgeName: x.Name, - Occurence: 0, + Occurrences: 0, BadgeList: [], }; return acc; @@ -194,10 +194,10 @@ export class ParticipantController extends BaseController { bArr = bArr.sort((a, b) => { return a.Badge.Name.localeCompare(b.Badge.Name); }); - const occurence = bArr.length; + const occurrences = bArr.length; badges[key].Badges[badgeName] = { BadgeName: badgeName, - Occurence: occurence, + Occurrences: occurrences, BadgeList: bArr, }; } From 6410c4aedb40b5389a8795fdf803de1cc92556fb Mon Sep 17 00:00:00 2001 From: vinay-debug <84920398+vinay-debug@users.noreply.github.com> Date: Wed, 24 May 2023 12:05:45 +0530 Subject: [PATCH 20/66] award exercise pipeline --- .../services/awards/participant.service.ts | 97 +++++++++---------- .../engine/schema.instance.service.ts | 4 +- .../fact.extractors/facts.db.connector.ts | 2 + .../exercise.physical.activity.fact.model.ts | 31 ++++++ .../data.extractors/data.extractor.ts | 4 + ...ercise.physical.activity.data.extractor.ts | 84 ++++++++++++++++ 6 files changed, 171 insertions(+), 51 deletions(-) create mode 100644 src/modules/fact.extractors/models/exercise.physical.activity.fact.model.ts create mode 100644 src/modules/processor/providers/implementation/data.extractors/exercise.physical.activity.data.extractor.ts diff --git a/src/database/services/awards/participant.service.ts b/src/database/services/awards/participant.service.ts index 9e5cc49..fd6a837 100644 --- a/src/database/services/awards/participant.service.ts +++ b/src/database/services/awards/participant.service.ts @@ -60,7 +60,7 @@ export class ParticipantService extends BaseService { var record = await this._participantRepository.save(participant); var context = await this._contextRepository.findOne({ - where: { + where : { ReferenceId : createModel.ReferenceId } }); @@ -73,10 +73,10 @@ export class ParticipantService extends BaseService { else { //Keep person context for this participant context = this._contextRepository.create({ - Type: ContextType.Person, + Type : ContextType.Person, ReferenceId : createModel.ReferenceId, Participant : record, - }) + }); const contextRecord = await this._contextRepository.save(context); logger.info(JSON.stringify(contextRecord, null, 2)); } @@ -90,13 +90,13 @@ export class ParticipantService extends BaseService { where : { id : id }, - relations: { - Client: true, + relations : { + Client : true, } }); var context = await this._contextRepository.findOne({ - where: { - ReferenceId: participant.ReferenceId + where : { + ReferenceId : participant.ReferenceId } }); return ParticipantMapper.toResponseDto(participant, context); @@ -112,32 +112,32 @@ export class ParticipantService extends BaseService { where : { ReferenceId : referenceId }, - select: { - id : true, - ReferenceId: true, - Client : { - id : true, - Name : true, - Code : true, - Email: true, + select : { + id : true, + ReferenceId : true, + Client : { + id : true, + Name : true, + Code : true, + Email : true, }, - BirthDate : true, - Prefix : true, - FirstName : true, - LastName : true, - CountryCode : true, - Phone : true, - Email : true, - Gender : true, - OnboardingDate: true, + BirthDate : true, + Prefix : true, + FirstName : true, + LastName : true, + CountryCode : true, + Phone : true, + Email : true, + Gender : true, + OnboardingDate : true, }, - relations: { - Client: true, + relations : { + Client : true, } }); var context = await this._contextRepository.findOne({ - where: { - ReferenceId: participant.ReferenceId + where : { + ReferenceId : participant.ReferenceId } }); return ParticipantMapper.toResponseDto(participant, context); @@ -249,7 +249,6 @@ export class ParticipantService extends BaseService { ErrorHandler.throwInternalServerError(error.message, 500); } }; - public awardBadge = async (id: string, badgeId: uuid, reason: string, acquiredDate = new Date()) : Promise => { @@ -265,10 +264,10 @@ export class ParticipantService extends BaseService { } }); var participantBadge = await this._participantBadgeRepository.create({ - Participant: participant, - Badge: badge, - AcquiredDate: acquiredDate, - Reason : reason + Participant : participant, + Badge : badge, + AcquiredDate : acquiredDate, + Reason : reason }); var record = await this._participantBadgeRepository.save(participantBadge); return record; @@ -286,11 +285,11 @@ export class ParticipantService extends BaseService { id : id } }, - relations: { - Badge: { - Category: true, + relations : { + Badge : { + Category : true, }, - Participant: true, + Participant : true, }, // select: { // Badge : { @@ -312,22 +311,22 @@ export class ParticipantService extends BaseService { const list = await this._participantBadgeRepository.find(search); const participantBadges = list.map(x => { return { - ParticipantId: id, - Badge: { - id : x.Badge.id, - Name: x.Badge.Name, + ParticipantId : id, + Badge : { + id : x.Badge.id, + Name : x.Badge.Name, Description : x.Badge.Description, - Category: { - id: x.Badge.Category.id, - Name: x.Badge.Category.Name, - ImageUrl: x.Badge.Category.ImageUrl, + Category : { + id : x.Badge.Category.id, + Name : x.Badge.Category.Name, + ImageUrl : x.Badge.Category.ImageUrl, }, ImageUrl : x.Badge.ImageUrl, }, - AcquiredDate: x.AcquiredDate, - Reason: x.Reason, - CreatedAt: x.CreatedAt - } + AcquiredDate : x.AcquiredDate, + Reason : x.Reason, + CreatedAt : x.CreatedAt + }; }); return participantBadges; } catch (error) { diff --git a/src/database/services/engine/schema.instance.service.ts b/src/database/services/engine/schema.instance.service.ts index ec406e1..c694c4e 100644 --- a/src/database/services/engine/schema.instance.service.ts +++ b/src/database/services/engine/schema.instance.service.ts @@ -292,13 +292,13 @@ export class SchemaInstanceService extends BaseService { if (filters.SchemaId) { search.where['Schema'] = { id: '' - } + }; search.where['Schema'].id = filters.SchemaId; } if (filters.ContextId) { search.where['Context'] = { id: '' - } + }; search.where['Context'].id = filters.ContextId; } diff --git a/src/modules/fact.extractors/facts.db.connector.ts b/src/modules/fact.extractors/facts.db.connector.ts index a6e3764..c9338c7 100644 --- a/src/modules/fact.extractors/facts.db.connector.ts +++ b/src/modules/fact.extractors/facts.db.connector.ts @@ -7,6 +7,7 @@ import { BadgeFact } from './models/bedge.facts.model'; import { MedicationFact } from './models/medication.fact.model'; import { DBLogger } from "./../../database/database.logger"; import { NutritionChoiceFact } from "./models/nutrition.choice.fact.model"; +import { ExercisePhysicalActivityFact } from "./models/exercise.physical.activity.fact.model"; /////////////////////////////////////////////////////////////////////////////////// const DATABASE_NAME = `awards_facts`; @@ -28,6 +29,7 @@ class FactsDatabaseConnector { MedicationFact, BadgeFact, NutritionChoiceFact, + ExercisePhysicalActivityFact, ], migrations : [], subscribers : [], diff --git a/src/modules/fact.extractors/models/exercise.physical.activity.fact.model.ts b/src/modules/fact.extractors/models/exercise.physical.activity.fact.model.ts new file mode 100644 index 0000000..99a924d --- /dev/null +++ b/src/modules/fact.extractors/models/exercise.physical.activity.fact.model.ts @@ -0,0 +1,31 @@ +import "reflect-metadata"; +import { + Column, + Entity, + PrimaryGeneratedColumn, +} from 'typeorm'; + +//////////////////////////////////////////////////////////////////////// + +@Entity({ name: 'exercise_physical_activity_facts' }) +export class ExercisePhysicalActivityFact { + + @PrimaryGeneratedColumn('uuid') + id : string; + + @Column({ type: 'uuid', nullable: false }) + ContextReferenceId : string; + + @Column({ type: 'uuid', nullable: true }) + RecordId : string; + + @Column({ nullable: true, default: false }) + PhysicalActivityQuestionAns: boolean; + + @Column({ nullable: true }) + RecordDate : Date; + + @Column({ nullable: true }) + RecordDateStr : string; + +} diff --git a/src/modules/processor/providers/implementation/data.extractors/data.extractor.ts b/src/modules/processor/providers/implementation/data.extractors/data.extractor.ts index 064f760..b18b0e7 100644 --- a/src/modules/processor/providers/implementation/data.extractors/data.extractor.ts +++ b/src/modules/processor/providers/implementation/data.extractors/data.extractor.ts @@ -9,6 +9,7 @@ import { DataExtractionInputParams, OutputParams, ProcessorResult } from '../../ import { MedicationDataExtractor } from './medication.data.extractor'; import { BadgeDataExtractor } from "./badge.data.extractor"; import { NutritionDataExtractor } from "./nutrition.data.extractor"; +import { ExercisePhysicalActivityDataExtractor } from "./exercise.physical.activity.data.extractor"; ////////////////////////////////////////////////////////////////////// @@ -61,6 +62,9 @@ export class DataExtractor implements IDataExtractor { else if (recordType === 'Nutrition') { return new NutritionDataExtractor(); } + else if (recordType === 'Exercise') { + return new ExercisePhysicalActivityDataExtractor(); + } return null; }; diff --git a/src/modules/processor/providers/implementation/data.extractors/exercise.physical.activity.data.extractor.ts b/src/modules/processor/providers/implementation/data.extractors/exercise.physical.activity.data.extractor.ts new file mode 100644 index 0000000..13b2d5f --- /dev/null +++ b/src/modules/processor/providers/implementation/data.extractors/exercise.physical.activity.data.extractor.ts @@ -0,0 +1,84 @@ +import { Repository } from "typeorm"; +import { FactsSource } from '../../../../fact.extractors/facts.db.connector'; +import { Context } from "../../../../../database/models/engine/context.model"; +import { DataExtractionInputParams, DataSamplingMethod, OutputParams, ProcessorResult } from '../../../../../domain.types/engine/engine.types'; +import { IExtractor } from "./extractor.interface"; +import { ExercisePhysicalActivityFact } from "../../../../../modules/fact.extractors/models/exercise.physical.activity.fact.model"; + +////////////////////////////////////////////////////////////////////// + +export class ExercisePhysicalActivityDataExtractor implements IExtractor { + + //#region Repositories + + _physicalActivityRepository: Repository = + FactsSource.getRepository(ExercisePhysicalActivityFact); + + //#endregion + + public extract = async ( + context: Context, + inputParams: DataExtractionInputParams, + outputParams: OutputParams) => { + + const filters = inputParams.Filters ?? {}; + var samplingMethod = filters['SamplingMethod'] as DataSamplingMethod; + if (!samplingMethod) { + samplingMethod = DataSamplingMethod.Any; + } + + const records = await this._physicalActivityRepository.find({ + where : { + ContextReferenceId : context.ReferenceId + }, + }); + + const groupedRecords = records.reduce((acc, obj) => { + const key = obj.RecordDateStr; + if (!acc[key]) { + acc[key] = []; + } + acc[key].push(obj); + return acc; + }, {}); + + const dayStats: { Day: string; Passed: boolean;}[] = []; + if (samplingMethod === DataSamplingMethod.Any) { + for (var grKey of Object.keys(groupedRecords)) { + const arr = groupedRecords[grKey]; + const passed = arr.some(obj => obj.PhysicalActivityQuestionAns === true); // Check only for one record per day + dayStats.push({ + Day : grKey, + Passed : passed, + }); + } + } + else { + for (var grKey of Object.keys(groupedRecords)) { + const arr = groupedRecords[grKey]; + const passed = arr.every(obj => obj.PhysicalActivityQuestionAns === true); // Check all records for the day + dayStats.push({ + Day : grKey, + Passed : passed, + }); + } + } + + const sorted = dayStats.sort((a, b) => Date.parse(a.Day) - Date.parse(b.Day)); + const transformed = sorted.map(x => { + return { + key : new Date(x.Day), + value : x.Passed, + }; + }); + + const result: ProcessorResult = { + Success : true, + Tag : outputParams.OutputTag, + Data : transformed + }; + + return result; + }; + +} From 01c774ad4893106c2b681150401800e13a8a42b1 Mon Sep 17 00:00:00 2001 From: vinay-debug <84920398+vinay-debug@users.noreply.github.com> Date: Thu, 25 May 2023 08:55:12 +0530 Subject: [PATCH 21/66] Postman collection with exercise schema --- .../awards service.postman_collection.json | 3225 ++++++++++++++++- 1 file changed, 3222 insertions(+), 3 deletions(-) diff --git a/postman/awards service.postman_collection.json b/postman/awards service.postman_collection.json index 85db54f..c3aac99 100644 --- a/postman/awards service.postman_collection.json +++ b/postman/awards service.postman_collection.json @@ -1,10 +1,9 @@ { "info": { - "_postman_id": "5848c7c3-39b2-41cc-835e-ecac30a028da", + "_postman_id": "d38423ff-1dbb-43c9-99a2-3c23bc63590e", "name": "Awards service", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "5510218", - "_collection_link": "https://solar-water-153775.postman.co/workspace/ReanCare~dff1f95d-5219-4d23-8d2c-af292e5a25ae/collection/5510218-5848c7c3-39b2-41cc-835e-ecac30a028da?action=share&creator=5510218&source=collection_link" + "_exporter_id": "15905052" }, "item": [ { @@ -8716,6 +8715,3226 @@ ] } ] + }, + { + "name": "exercise badges", + "item": [ + { + "name": "Create badge category", + "item": [ + { + "name": "Create badge category", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"BADGE_CATEGORY_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Participant is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Exercise\",\r\n \"Description\": \"Badge category for exercise related badges\",\r\n \"ImageUrl\": \"https://e7.pngegg.com/pngimages/626/893/png-clipart-blue-and-white-check-logo-facebook-social-media-verified-badge-logo-vanity-url-blue-checkmark-blue-angle.png\"\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/badge-categories", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badge-categories" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get badge category by id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/badge-categories/{{BADGE_CATEGORY_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badge-categories", + "{{BADGE_CATEGORY_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + }, + { + "name": "Schema-7-Day exercise badge", + "item": [ + { + "name": "Create badge", + "item": [ + { + "name": "Create badge", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"BADGE_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Participant is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + "\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"CategoryId\": \"{{BADGE_CATEGORY_ID}}\",\r\n \"Name\": \"7-Day Physical Activity\",\r\n \"Description\": \"Badge awarded doing exercise for 7-days consistently.\",\r\n \"ImageUrl\": \"https://e7.pngegg.com/pngimages/626/893/png-clipart-blue-and-white-check-logo-facebook-social-media-verified-badge-logo-vanity-url-blue-checkmark-blue-angle.png\"\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/badges", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badges" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get badge by id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/badges/{{BADGE_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badges", + "{{BADGE_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + }, + { + "name": "Create schema", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"SCHEMA_ID\", jsonRes.Data.id);\r", + " pm.environment.set(\"SCHEMA_ROOT_NODE_ID\", jsonRes.Data.RootNode.id);\r", + " pm.environment.set(\"NODE_01_ID\", jsonRes.Data.RootNode.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Client');\r", + " pm.expect(jsonRes.Data.Client).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", + " pm.expect(jsonRes.Data).to.have.property('RootNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Exercise 7-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient does physical activity(exercise) for 7 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{EXERCISE_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract exercise data\",\r\n \"Description\": \"Extract exercise data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract exercise data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Exercise\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"Any\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting exercise data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:Exercise\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/schema", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "schema" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "01 - Get root Node - Extract nutrition data", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_01_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is retrieved\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_01_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_01_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "02 - Create next node - Calculate Continuity", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_02_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_01_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Calculate continuity\",\r\n \"Description\": \"This execution step involves calculating the continuity for doing exercise consecutively for 7-days.\",\r\n \"Action\": {\r\n \"ActionType\": \"Process-Data\",\r\n \"Name\": \"Calculate Continuity\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Exercise\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Extract-Data:Exercise\",\r\n \"DataActionType\": \"Calculate-Continuity\",\r\n \"KeyDataType\": \"Date\",\r\n \"KeyName\": \"Date\",\r\n \"ValueDataType\": \"Boolean\",\r\n \"ValueName\": \"PhysicalActivityQuestionAns\",\r\n \"Value\": true,\r\n \"Operator\": \"Equal\",\r\n \"ContinuityCount\": 7\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Processing records for 7-day exercise choice continuity\",\r\n \"OutputTag\": \"Calculate-Continuity:Exercise\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 01", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_02_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_01_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_01_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "03 - Create next node - Extract existing badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_03_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_02_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Get existing badges\",\r\n \"Description\": \"Extract existing 7-day exercise badges for the participant.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract-Badges\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Database\",\r\n \"InputTag\": \"Badge\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"Exercise\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"7-Day Physical Activity\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting 7-day exercise badges\",\r\n \"OutputTag\": \"Extract-Data:Badge\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 02", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_03_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_02_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_02_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "04 - Create next node - Compare badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_04_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_03_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Compare badges\",\r\n \"Description\": \"Compare calculated badges against existing badges for 7-day exercise physical activity.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Compare-Data\",\r\n \"Name\": \"Compare badges\",\r\n \"Description\": \"Compare calculated badges against existing badges for 7-day exercise physical activity\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Calculate-Continuity:Exercise\",\r\n \"SecondaryInputTag\": \"Extract-Data:Badge\",\r\n \"DataActionType\": \"Find-Range-Difference\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"Exercise\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"7-Day Physical Activity\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Comparing badges and get updated badge list for 7-day exercise physical activity badges.\",\r\n \"OutputTag\": \"Compare-Data:Badge\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 03", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_04_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_03_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_03_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "05 - Create next node - Store updated badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_05_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_04_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Store updated badges\",\r\n \"Description\": \"Store updated 7-day exercise physical activity badges for the participant.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Store-Data\",\r\n \"Name\": \"Store updated badges\",\r\n \"Description\": \"Store updated 7-day exercise physical activity badges for the participant.\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Compare-Data:Badge\",\r\n \"StorageKeys\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"Exercise\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"7-Day Physical Activity\"\r\n },\r\n {\r\n \"Key\": \"BadgeId\",\r\n \"Value\": \"{{BADGE_ID}}\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting 7-day exercise physical activity badges\",\r\n \"OutputTag\": \"Store-Data:Badge\",\r\n \"DestinationType\": \"Database\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 04", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_05_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_04_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_04_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get schema by Id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Client');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", + " pm.expect(jsonRes.Data).to.have.property('RootNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/engine/schema/{{SCHEMA_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "schema", + "{{SCHEMA_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + }, + { + "name": "Schema-15-Day exercise badge", + "item": [ + { + "name": "Create badge", + "item": [ + { + "name": "Create badge", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"BADGE_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Participant is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + "\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"CategoryId\": \"{{BADGE_CATEGORY_ID}}\",\r\n \"Name\": \"15-Day Physical Activity\",\r\n \"Description\": \"Badge awarded doing exercise for 15-days consistently.\",\r\n \"ImageUrl\": \"https://e7.pngegg.com/pngimages/626/893/png-clipart-blue-and-white-check-logo-facebook-social-media-verified-badge-logo-vanity-url-blue-checkmark-blue-angle.png\"\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/badges", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badges" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get badge by id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/badges/{{BADGE_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badges", + "{{BADGE_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + }, + { + "name": "Create schema", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"SCHEMA_ID\", jsonRes.Data.id);\r", + " pm.environment.set(\"SCHEMA_ROOT_NODE_ID\", jsonRes.Data.RootNode.id);\r", + " pm.environment.set(\"NODE_01_ID\", jsonRes.Data.RootNode.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Client');\r", + " pm.expect(jsonRes.Data.Client).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", + " pm.expect(jsonRes.Data).to.have.property('RootNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Exercise 15-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient does physical activity(exercise) for 15 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{EXERCISE_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract exercise data\",\r\n \"Description\": \"Extract exercise data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract exercise data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Exercise\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"Any\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting exercise data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:Exercise\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/schema", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "schema" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "01 - Get root Node - Extract nutrition data", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_01_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is retrieved\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_01_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_01_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "02 - Create next node - Calculate Continuity", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_02_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_01_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Calculate continuity\",\r\n \"Description\": \"This execution step involves calculating the continuity for doing exercise consecutively for 15-days.\",\r\n \"Action\": {\r\n \"ActionType\": \"Process-Data\",\r\n \"Name\": \"Calculate Continuity\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Exercise\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Extract-Data:Exercise\",\r\n \"DataActionType\": \"Calculate-Continuity\",\r\n \"KeyDataType\": \"Date\",\r\n \"KeyName\": \"Date\",\r\n \"ValueDataType\": \"Boolean\",\r\n \"ValueName\": \"PhysicalActivityQuestionAns\",\r\n \"Value\": true,\r\n \"Operator\": \"Equal\",\r\n \"ContinuityCount\": 15\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Processing records for 15-day exercise choice continuity\",\r\n \"OutputTag\": \"Calculate-Continuity:Exercise\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 01", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_02_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_01_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_01_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "03 - Create next node - Extract existing badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_03_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_02_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Get existing badges\",\r\n \"Description\": \"Extract existing 15-day exercise badges for the participant.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract-Badges\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Database\",\r\n \"InputTag\": \"Badge\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"Exercise\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"15-Day Physical Activity\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting 15-day exercise badges\",\r\n \"OutputTag\": \"Extract-Data:Badge\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 02", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_03_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_02_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_02_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "04 - Create next node - Compare badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_04_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_03_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Compare badges\",\r\n \"Description\": \"Compare calculated badges against existing badges for 15-day exercise physical activity.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Compare-Data\",\r\n \"Name\": \"Compare badges\",\r\n \"Description\": \"Compare calculated badges against existing badges for 15-day exercise physical activity\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Calculate-Continuity:Exercise\",\r\n \"SecondaryInputTag\": \"Extract-Data:Badge\",\r\n \"DataActionType\": \"Find-Range-Difference\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"Exercise\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"15-Day Physical Activity\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Comparing badges and get updated badge list for 15-day exercise physical activity badges.\",\r\n \"OutputTag\": \"Compare-Data:Badge\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 03", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_04_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_03_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_03_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "05 - Create next node - Store updated badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_05_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_04_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Store updated badges\",\r\n \"Description\": \"Store updated 15-day exercise physical activity badges for the participant.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Store-Data\",\r\n \"Name\": \"Store updated badges\",\r\n \"Description\": \"Store updated 15-day exercise physical activity badges for the participant.\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Compare-Data:Badge\",\r\n \"StorageKeys\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"Exercise\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"15-Day Physical Activity\"\r\n },\r\n {\r\n \"Key\": \"BadgeId\",\r\n \"Value\": \"{{BADGE_ID}}\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting 15-day exercise physical activity badges\",\r\n \"OutputTag\": \"Store-Data:Badge\",\r\n \"DestinationType\": \"Database\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 04", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_05_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_04_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_04_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get schema by Id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Client');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", + " pm.expect(jsonRes.Data).to.have.property('RootNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/engine/schema/{{SCHEMA_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "schema", + "{{SCHEMA_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + }, + { + "name": "Schema-30-Day exercise badge", + "item": [ + { + "name": "Create badge", + "item": [ + { + "name": "Create badge", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"BADGE_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Participant is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + "\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"CategoryId\": \"{{BADGE_CATEGORY_ID}}\",\r\n \"Name\": \"30-Day Physical Activity\",\r\n \"Description\": \"Badge awarded doing exercise for 30-days consistently.\",\r\n \"ImageUrl\": \"https://e7.pngegg.com/pngimages/626/893/png-clipart-blue-and-white-check-logo-facebook-social-media-verified-badge-logo-vanity-url-blue-checkmark-blue-angle.png\"\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/badges", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badges" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get badge by id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/badges/{{BADGE_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badges", + "{{BADGE_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + }, + { + "name": "Create schema", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"SCHEMA_ID\", jsonRes.Data.id);\r", + " pm.environment.set(\"SCHEMA_ROOT_NODE_ID\", jsonRes.Data.RootNode.id);\r", + " pm.environment.set(\"NODE_01_ID\", jsonRes.Data.RootNode.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Client');\r", + " pm.expect(jsonRes.Data.Client).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", + " pm.expect(jsonRes.Data).to.have.property('RootNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Exercise 30-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient does physical activity(exercise) for 30 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{EXERCISE_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract exercise data\",\r\n \"Description\": \"Extract exercise data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract exercise data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Exercise\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"Any\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting exercise data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:Exercise\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/schema", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "schema" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "01 - Get root Node - Extract nutrition data", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_01_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is retrieved\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_01_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_01_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "02 - Create next node - Calculate Continuity", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_02_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_01_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Calculate continuity\",\r\n \"Description\": \"This execution step involves calculating the continuity for doing exercise consecutively for 30-days.\",\r\n \"Action\": {\r\n \"ActionType\": \"Process-Data\",\r\n \"Name\": \"Calculate Continuity\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Exercise\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Extract-Data:Exercise\",\r\n \"DataActionType\": \"Calculate-Continuity\",\r\n \"KeyDataType\": \"Date\",\r\n \"KeyName\": \"Date\",\r\n \"ValueDataType\": \"Boolean\",\r\n \"ValueName\": \"PhysicalActivityQuestionAns\",\r\n \"Value\": true,\r\n \"Operator\": \"Equal\",\r\n \"ContinuityCount\": 30\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Processing records for 30-day exercise choice continuity\",\r\n \"OutputTag\": \"Calculate-Continuity:Exercise\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 01", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_02_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_01_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_01_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "03 - Create next node - Extract existing badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_03_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_02_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Get existing badges\",\r\n \"Description\": \"Extract existing 30-day exercise badges for the participant.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract-Badges\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Database\",\r\n \"InputTag\": \"Badge\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"Exercise\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"30-Day Physical Activity\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting 30-day exercise badges\",\r\n \"OutputTag\": \"Extract-Data:Badge\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 02", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_03_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_02_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_02_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "04 - Create next node - Compare badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_04_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_03_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Compare badges\",\r\n \"Description\": \"Compare calculated badges against existing badges for 30-day exercise physical activity.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Compare-Data\",\r\n \"Name\": \"Compare badges\",\r\n \"Description\": \"Compare calculated badges against existing badges for 30-day exercise physical activity\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Calculate-Continuity:Exercise\",\r\n \"SecondaryInputTag\": \"Extract-Data:Badge\",\r\n \"DataActionType\": \"Find-Range-Difference\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"Exercise\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"30-Day Physical Activity\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Comparing badges and get updated badge list for 30-day exercise physical activity badges.\",\r\n \"OutputTag\": \"Compare-Data:Badge\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 03", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_04_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_03_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_03_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "05 - Create next node - Store updated badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_05_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_04_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Store updated badges\",\r\n \"Description\": \"Store updated 30-day exercise physical activity badges for the participant.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Store-Data\",\r\n \"Name\": \"Store updated badges\",\r\n \"Description\": \"Store updated 30-day exercise physical activity badges for the participant.\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Compare-Data:Badge\",\r\n \"StorageKeys\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"Exercise\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"30-Day Physical Activity\"\r\n },\r\n {\r\n \"Key\": \"BadgeId\",\r\n \"Value\": \"{{BADGE_ID}}\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting 30-day exercise physical activity badges\",\r\n \"OutputTag\": \"Store-Data:Badge\",\r\n \"DestinationType\": \"Database\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 04", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_05_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_04_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_04_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get schema by Id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Client');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", + " pm.expect(jsonRes.Data).to.have.property('RootNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/engine/schema/{{SCHEMA_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "schema", + "{{SCHEMA_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + } + ] } ] } From a2e982f0cc6dd241ea82c4819fe77a290ea65772 Mon Sep 17 00:00:00 2001 From: tabbasum-rean Date: Wed, 31 May 2023 11:23:11 +0530 Subject: [PATCH 22/66] Get badge images API and added badge images in S3 through seeder --- .../15-Day Healthy Nutrition Choice.png | Bin 0 -> 5138 bytes .../15-Day Medication Adherence.png | Bin 0 -> 5066 bytes .../15-Day Mental Well-being..png | Bin 0 -> 5798 bytes .../15-Day Physical Activity.png | Bin 0 -> 5058 bytes .../stock.badge.images/15-Day Vitals.png | Bin 0 -> 1736 bytes .../30-Day Healthy Nutrition Choice.png | Bin 0 -> 5969 bytes .../30-Day Medication Adherence.png | Bin 0 -> 5487 bytes .../30-Day Mental Well-being..png | Bin 0 -> 5296 bytes .../30-Day Physical Activity.png | Bin 0 -> 1962 bytes .../stock.badge.images/30-Day Vitals.png | Bin 0 -> 1971 bytes .../7-Day Healthy Nutrition Choice.png | Bin 0 -> 5960 bytes .../7-Day Medication Adherence.png | Bin 0 -> 5674 bytes .../7-Day Mental Well-being.png | Bin 0 -> 5800 bytes .../7-Day Physical Activity.png | Bin 0 -> 5869 bytes .../stock.badge.images/7-Day Vitals.png | Bin 0 -> 2026 bytes seed.data/role.privileges.json | 8 +- src/api/awards/badge/badge.controller.ts | 17 +++ src/api/awards/badge/badge.routes.ts | 1 + .../participant/participant.controller.ts | 6 +- src/api/base.validator.ts | 31 +++++ .../file.resource/file.resource.controller.ts | 93 ++++++++++++- .../file.resource/file.resource.routes.ts | 2 + src/common/helper.ts | 9 ++ src/database/database.connector.ts | 4 + .../awards/badge.stock.image.mapper.ts | 23 ++++ .../mappers/general/file.resource.mapper.ts | 31 +++++ .../models/awards/badge.stock.image.model.ts | 42 ++++++ .../models/general/file.resource.model.ts | 26 +++- .../general/file.resource.version.model.ts | 53 +++++++ .../services/awards/participant.service.ts | 25 ++++ .../badge.stock.image.service.ts | 57 ++++++++ .../services/general/file.resource.service.ts | 130 ++++++++++++++++++ .../badge.stock.image.domain.model.ts | 7 + .../badge.stock.image.dto.ts | 7 + .../general/file.resource.domain.types.ts | 1 + .../file.resource.domain.model.ts | 26 ++++ .../file.resource/file.resource.dto.ts | 25 ++++ .../file.resource.search.types.ts | 29 ++++ .../file.resource/file.resource.types.ts | 31 +++++ .../file.storage.service.interface.ts | 2 +- .../providers/aws.s3.file.storage.service.ts | 2 +- src/modules/storage/storage.service.ts | 6 +- src/startup/router.ts | 3 + src/startup/seeder.ts | 54 +++++++- 44 files changed, 730 insertions(+), 21 deletions(-) create mode 100644 assets/images/stock.badge.images/15-Day Healthy Nutrition Choice.png create mode 100644 assets/images/stock.badge.images/15-Day Medication Adherence.png create mode 100644 assets/images/stock.badge.images/15-Day Mental Well-being..png create mode 100644 assets/images/stock.badge.images/15-Day Physical Activity.png create mode 100644 assets/images/stock.badge.images/15-Day Vitals.png create mode 100644 assets/images/stock.badge.images/30-Day Healthy Nutrition Choice.png create mode 100644 assets/images/stock.badge.images/30-Day Medication Adherence.png create mode 100644 assets/images/stock.badge.images/30-Day Mental Well-being..png create mode 100644 assets/images/stock.badge.images/30-Day Physical Activity.png create mode 100644 assets/images/stock.badge.images/30-Day Vitals.png create mode 100644 assets/images/stock.badge.images/7-Day Healthy Nutrition Choice.png create mode 100644 assets/images/stock.badge.images/7-Day Medication Adherence.png create mode 100644 assets/images/stock.badge.images/7-Day Mental Well-being.png create mode 100644 assets/images/stock.badge.images/7-Day Physical Activity.png create mode 100644 assets/images/stock.badge.images/7-Day Vitals.png create mode 100644 src/database/mappers/awards/badge.stock.image.mapper.ts create mode 100644 src/database/models/awards/badge.stock.image.model.ts create mode 100644 src/database/models/general/file.resource.version.model.ts create mode 100644 src/database/services/badge.stock.images/badge.stock.image.service.ts create mode 100644 src/domain.types/badge.stock.image/badge.stock.image.domain.model.ts create mode 100644 src/domain.types/badge.stock.image/badge.stock.image.dto.ts create mode 100644 src/domain.types/general/file.resource/file.resource.domain.model.ts create mode 100644 src/domain.types/general/file.resource/file.resource.dto.ts create mode 100644 src/domain.types/general/file.resource/file.resource.search.types.ts create mode 100644 src/domain.types/general/file.resource/file.resource.types.ts diff --git a/assets/images/stock.badge.images/15-Day Healthy Nutrition Choice.png b/assets/images/stock.badge.images/15-Day Healthy Nutrition Choice.png new file mode 100644 index 0000000000000000000000000000000000000000..9168a3c3472a450e86597d38dcfa5480b496b423 GIT binary patch literal 5138 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 AjsO4v literal 0 HcmV?d00001 diff --git a/assets/images/stock.badge.images/15-Day Medication Adherence.png b/assets/images/stock.badge.images/15-Day Medication Adherence.png new file mode 100644 index 0000000000000000000000000000000000000000..66bd62684ad1f8aa06b4b7284678f0ff7aa697d5 GIT binary patch literal 5066 zcmV;*6E*CKP)pF(N|EnO}E~oQ- z9sN3{pU$Vt<(~oOI^eJXp_G!6fgz<*6D|WP*WVAtgA#YeB4a>h#N^jP;zKbGmL3x( zzYvlOfMOI3mN(>p$oV%Ray#Ae_{;K#nh^ONL2^3Z?=Ql!aO8CTg+a2Qp;+k{5c$y* zxdy=~CdbdG$n|s&kH0#26p<%fGfq-0A zFovN>a>#vfj1S~&2IR-sjPnzW_00n`iiOn9f6kAb8S*o-%p51m@O4mdsD0$n>ofJl zx%1~o%x&`DmOlrMmOp>?k%MiXYNo}2%TJ(&|Dl$1lA~Nm4K^Mq#oRtkHf#Wl zWghw<$9-q4gc)K#E5nSk(VHL`jHycG2mzw|55nUV$S9AGVf2O^WAq#GpwQ41HRfm;$)R?V13k`JT0q{%j|-7gG**pAwEW$bWzAwb&@i-s*f;sp z8{s#Wx2TDCKSaweA+^B=avBfzmigS3@S+PEf_n2)w3IKA+O6q;grfy@^rwf<_lFt1 zB1P2F?|sZIJNIRgkOBdLc&Ovk?HMoj*pO^Y?_3DE7Y(L`pc%J%R6M^uzdNZ!WTWGj zy*jKWan=+bN2iw?N-B#l=dthbRX{{UP~Vwe2pNr_(OFh$MDVb0lv6CDF*I~7G)Vig zCK&rRIUW6%&PKy6YS_Ip9FM#L#SeX0xLlENn23tbZ}v4X9;lkgO8`G+j|!JF6b>Cj zV=~jWdwpm$v4!zypnRN<36-8eBV?5(ILzy4I1zzknZRhc_jfrYR16l5@b_N{jwn0U z?1kLN_3%)!F=xJhjMuee`oLk(XTNS?xSZM>u%3|7$j2373sn*;CY)I|>DEBAerrw+ zi-m*7K8ac9>c$$o_YW4C*>2N|26O#$YaLa1rlQj+vdZ9Taj{3LDbmq|jC$)5jnP=- z)Eua$C!nL6W$9#eZ2xt2qi6-I5-V9ERn33U+^W zWW9_*;nFbKB61|v{%ANHGGh(t0m+daD$AZEJ^H?11ETL=go6l|X7m`zfpj#}ev|AN zV35R7QPuB% zf+7$oPkLk|k#1T{1i)4JB<;+qarBBU-_6;!h4G<*dJ4ndE$ z(E{>HiI6U6=_zq?0kQx@$d@_k!5o@zr>@ZQL6RRtcg|@;CS~UB?1SowuIS8JgQ9714c_d@c`0c zbMuPZ)RQOC82|BlJ|S2uC}4UC513o(iO0!z9oZgivn%zTf@6I9R%>nI`?AY=b;i&j zTIx9u-*xC*55_ljFex|$o6*py>QWOB+g$O`Eu4q%I&!7MZP}iUhDp`u+uU#g;-PD4 zDVVV2N{3gjvmXt}50Og`+ek}qzLI82hw#4HOf<*>WhL zJS}aITFxl3n0n-JEX9qn8ww-J(@V9~R7x#4vFJQ<6h(@OwmR;1&;zHIN^n4n&TEk) zts6^|QochyU}~w8X|FiXiY(7jiyNbO*d6rHO)~A(+f&Gz-Mc(;WO8GKLlUM&7tZlj zD>z(EtcaWmZx%NOI255xrW}r26*w4xIzC}UbJ91PVayt z<4ni!pNGVkTb)0s7dc_(MLx{F2M&?UD?^-^scUC;t9VUgUh2|MwKGcw96XhLrYZW| zr828C(g2(zBhtQM(t_b&uSv(UYpZgvtQmllflcfpm#!PY5%L|*d2r~2`x=XCRVF_M za_~?{z8j7JJKUxmC+<4ja|c0Y@k5d1SjST7gf@yGiQ1H7%>yU{FP)! z3+<38INY`zCuYLHJSBr4L#Wu`Oh6a1<8;Ur&TWg=Vu=OK+LHVj&`@E;wr@$asR_PU z%NLpC5p!7S7iTZ$d&Uz`azUdP;rb|hybb$GF8?^MT1y9=iKFJQ%ELo?J;c@c6YuuI z0ruh8F>rv&R~@n)f%T0IKd570x_b$Z`a28$(lJh>pqMWNhYPK5sO3gQNr2I_t{NP& z1srH4T@Y~CqP4Htud7FdsOd=50*-XC+RBpEusX{>U;`iSSa0jqBJ6OnwJ+r#43o=k zq%&RAUMba0)=EKT7@WhQN?;le6I~aT-j%HK@wZuL`93&^J?lz)wBb!jkq3uPtc!a2 zMQ-k@9SPFADsbGZ!NEd443u_;e1}V|nS1VZ3&(_q+y#eiQ}1#K`!HDO>H@CRB-YG( z&#QZIus(1uFzHHJ6BkC6yXeqyfpyLTC*yH$NZ+aZa7@lLFlRAk1r1f;2p2=SARMq@ z$3*v2djIoF{G%m7E2!$hymWI;G+dL-97S`|YP^)9oPQg33N zd1E0pER!4v4oS^ilB;2@O69235~2Wzs>M{;GDK1&D`@hV62HO1^fW z-ANJ-T_zm{AMdGlHtimXJjwYjp=ZeP;-{ErjY1=h;Avf&{7sGL%(DVUYAb zi^TgZqL>^l+NEC!F-ZY5t&A9TqAq(@Lq`T9#<5f77Yghbx4(Co$<`g#^leM!EY zT5$*(oV;S8-F-%o9-0mpzTpgKCEfOutqYTtlm7iIZ7+vI7Y34@iMUriUj+}5gN8vm z+WIcE6TJ8fy-RDiozORUywa1BGx$1I2hut}?DC$)nlj?%FZiasc6fqGq^NqS@X1*%|z}DMl?% zp>f0|oA~-w2HXcH;8=fI+T+)81_MP~9F8mA8tUk+H5}7KUlaGQM%nQUm=ZwTBk(x! zpzVul`o_^C?)OIF0u0jdcJ=rb(#oH8!y5p@(7?iE{+9b_r*L5e9_u$~&CF>|8-tt+ zIL6$%`Nx6h05mMRt@w5X98-2N)Lqu;)@Dzl8!jS>VW4@T=)ogsjPCsOb<8+JGnS2q z@LJXmkT`rI*V9TJoVPyM!QXt-`DDhx&F?IM$A9ge>5{7;5QPJyB4q&I|7k~Yhi)VweN?>CX)f>24w^`IQj&ok@J+1dJ?8B#z zZO=r7y!3wYW=mmWC4Y=zARHsWfzJYuM??LpsdUZZm0rPP`rk_kUzpF9@Y@%>|m7 zqMuLH=i<=z(SSS@*4qdjPfk$KiT=Sq+ zg&aHUKYnz1fCF5sxvcjE_t#tC7ZW5%Av6SsAP#BB_M)CSKAr;%b(JwhQddn?FD3jF zn{p^CYMd{HCz8?f*j*E4ieblvq7EV<&saiO z4AOWv{LVOrjRuXR^jjoO6rC9j=eH*q_s22qRPj}5tXRiI zKWgb9ND=rQHtl?g0mn`tdt-#rHqqcX5QqUI5*!l{x2f(9*%&aQ!7&3NKNALNEf^8u zXy)yG@^`{8U_^yu2GV{>M6ovvBQhNQ8SoPk^(l)6Wf32aMIv3+D6!iwnzsu^j5yXr z+J*$GL?||Yt!>egqr|bwnvsdiOu9kM>O_49i->V-RWiz-4MP;6JL_tA;l%bMdWZTm zaWG<67>#!LJb5k-@?0Jb86&7w^<*tAm+K znQE4cFZ}rKk>uuYjzQQ-^Y{faIyE!?WL_PD>r$TGT8Zb+C|y z(<~Kru&~mKG}IBiO{+*j9Xl#eJzgDb*M1BBaCNYqyHDyzt7HG}llsBx_++nZ{a76Q zfKubd@$sg$@`*UUD7SbT4))y^zT#mxzCAFYdK8ZDZ<;>{$1lpRAA*CGN0uHPj^fbb zW5e;w`z@l!@#8n2Mva60{II4fW*i3`pTOhAamZm!JXRbBoikF$iQ}BhM1tecQ&-B^ za2$NbTM-wI!*8;R3C9VCHSzN<^(BsT4$9<58}^Udz~an{-8omfTddB!KYni*IdbI4 gkt0Wr969#HKacQslD&9Exc~qF07*qoM6N<$f`zED%>V!Z literal 0 HcmV?d00001 diff --git a/assets/images/stock.badge.images/15-Day Mental Well-being..png b/assets/images/stock.badge.images/15-Day Mental Well-being..png new file mode 100644 index 0000000000000000000000000000000000000000..e1d76039f7a504542487383a91b4aecb9661667b GIT binary patch literal 5798 zcmV;X7Fp?uP)fGt|oVm~c|NljBgEht_`~Uy|3UpFVQvgZ-|JJB?B&ORDEUc{n02T&GL_t(|+T>k{ za^olv9Sa{-Naj@X|DU?L1x?c+85}3e)>JZ^i7Y?Aetpoi{{8!z^|;*cw_#nc*XOW? zFXP|t_siqo|7s053?PgUJeBIk)vs&#Ua1kA+y4WV0g30j`X;spSSC>Jm%q#k2a1sy z4ZQ}g3{3f>koZuHt7|e=-w!mo-T#*1TmmeH)#R=Tk;~t)kt+g5(pLT^A~+V$=XY~( z_1&N&zuRaYw`X)U$5;2ODRLpe`0ktL93a=<3CQL8B-VFx7LG9-`K@4dy2H`v&cR{& z>DPZ5Lmo32yexS?{9Su4tU|&V(uSJjfMs5b#lzMB7!S7Q<3QLvDD~H zhz78h@8d#>+R7|UpGuG^*610wnpcH14##rw+b0@Ipc>N}-iwdMVOueBWr;wpZ$8gp zE|Z}M9E>IL+Tb{vu1MpUjfffJ<-^dx3}tyE{Y&J~+WT9~VD29!qB07`u+$4)RxY+8 z{lvxRp!ysIg zH!LjQsKM9wuvp9Y8818A%66re>zIQ4I36e(>+Q1ES!zb(1UV+AY4=*IE(Hc7e-;lE z4GHXIx0Vw^D$Pta>tD@84CY7ixFcw+vH|XYw3c(^(2kJqYn4>-Iref#RMZ5jv0KXt zI0kY^gldk07zB?WiN`K+G{U
u)LHCxaDm%#DpeR7>(P? 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 literal 0 HcmV?d00001 diff --git a/assets/images/stock.badge.images/30-Day Mental Well-being..png b/assets/images/stock.badge.images/30-Day Mental Well-being..png new file mode 100644 index 0000000000000000000000000000000000000000..4fa044c280a94c2450e230975c6a24bf13741d5e GIT binary patch literal 5296 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 literal 0 HcmV?d00001 diff --git a/assets/images/stock.badge.images/30-Day Vitals.png b/assets/images/stock.badge.images/30-Day Vitals.png new file mode 100644 index 0000000000000000000000000000000000000000..cd39e62478dca72099d7ec58ef7f8a5dbf986c08 GIT binary patch literal 1971 zcmV;k2Tb^hP)F+{@W+;x*+YW0P?vn_{kLOvlr%~1m>v|@xL16tSQ==Eb6x^{n#M- z(<s$3Y_ZLf# zuhMRq!Q^Mu+`bgkN7n!V29QZaK~z}7?V0Iz+DH(EZ7_yljD3;_2_Y%kH)}&|&e+NO zKh{)Lw-yA5H77r2%IBDvmOd`GtE*a_ySu*{gZtsAnh6A3XH~Q50iBe})Zo zCS@=f^jg82;4Zk{w?Vgmg!= z^dUts;5%G+=jC)a=!+_rD`2Rf%}F#}$)};2r7-r1o;;J!u41hO7IL_=Ty#FPvMdwX zy_4qhv5yz4RzaTVusn9dV57c5Z1t2J9CTxpp;+uI3rqd?k3I2QpK#%drBV(apUNRk zVX0Y&-hb?k_lRHMGr!Z9<94W&8}Ix^P`w|W8A9o|gKCaiGD16Co*PW|M%ouBddXy) z3g&mvJtCU&&T@oW$os+r>AP9_f7-Dxj_qktCSY7g4;GziZt(14uyM4lLmb5u5o zR;@RoiAHR`hRBhR?@T6yrk6=TvU_c^pJEd2H_$+vo5i2zJV!VomyFD1$1O=R!1QQ} z7C`Z0`@V>|!&l_5K? zTk?ix$4_lbv2L}fVKz^y!eJDh;Fs>>a8RK$t8E@fW;KgTCK`Y1yR~T}edsh^pGRy7 z{R8MO6}@*>bAatr-YxeQzD%c?RBLFrB}L>4J;ADGYAc#J=}=XL&#tA&X=ql}=Hy3I z?5XW-bljLo%D(?fqLx#Mt zB~xC_(U}e5$sy1sTL!pIZ}{7W1g%SkFZA;2^_=$t{se~H1b$P*LIX_;ec0Lwl=A9) z&Co_+FA$mW@CB$n%-4?(KfOy@e7T&myENEIox<28>#B*k)nFn#WG-(HOJJ7 zUK=Mo0a3J`*`C2`Zgnj-$Ahz2G_cC-d|uSRl(CVVnYNr2Eoi%ewY2p69+_R%oViwZ z9J^R4<}4}5e$$V({S!G-<%pq`vVG2Wft;3o)2Q+T{phxAgem>rs)-CVv1|)AE|u9w zDBD$c+ZG+SJ$6uz)KfdJEKwml+>ecC^R)5vd|UL9Z7|!JRc;$vUhZ!o1$9WfWzjdQ zKA&mdbo*@U3vnAl_$q4$CNfA zZijhXG(IJnWC=2uFU;VXIo( zQmstb6Qg5M80y6aSnQnepN2GSC$xSZh4ifl3n$ZyH9#$yxWL6M#ozs}5s>v@qf&C^Ol|!368EX3@kK%=J5U@(KKX!)9RNU{IQZQoos%P7j~IMI6AWMMjUBd}agg)e z%hGVQ0z~$5w_l60Ilj#*`RPLo&lbfYBDxO}4o=y{>+i4uo zNoWwnDgK=lqgSD)Q+KvVQ`}PGR+lum?}x^}T#FvJ zH0Jm!bnA_S*9*~K4%%GB>t*P>*YC%#`TlyN|3Usw#J}6tw}xj)ZgKzs002ovPDHLk FV1h6|=n4P; literal 0 HcmV?d00001 diff --git a/assets/images/stock.badge.images/7-Day Healthy Nutrition Choice.png b/assets/images/stock.badge.images/7-Day Healthy Nutrition Choice.png new file mode 100644 index 0000000000000000000000000000000000000000..17e89245bf4562e0c8ac2b5587afb5676196d89d GIT binary patch literal 5960 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 QFaQ7m07*qoM6N<$f^2u}5C8xG literal 0 HcmV?d00001 diff --git a/assets/images/stock.badge.images/7-Day Mental Well-being.png b/assets/images/stock.badge.images/7-Day Mental Well-being.png new file mode 100644 index 0000000000000000000000000000000000000000..b2c0dc62ed97456f49b87c84de74749e72bae04e GIT binary patch literal 5800 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 DHI+wc literal 0 HcmV?d00001 diff --git a/assets/images/stock.badge.images/7-Day Vitals.png b/assets/images/stock.badge.images/7-Day Vitals.png new file mode 100644 index 0000000000000000000000000000000000000000..a5307534095830f3cd37d7bbe3a8904251e60872 GIT binary patch literal 2026 zcmV zW#zh`@5Za%vX|nwoA1V}^5NF)*vjwHyWX*u=)0WLq>1mwtG9n*#*k~gg=yTgnZuEG z;J&8p&9>#nvF6IS@ZHeXt(451f$Y@7>CeB_sgBa3g2|O|&6;=JxS*$YSMJxx&!dar zu#oxj>*lzanPW)>c!uQw001>~QchC<@zOXy7_a{DP+au+4E5QbwXHjd+* zb1cRXNeD2AJJ^~0|6jK1mNwyP$_mUw91Zb>c8&CL-unm&#P11{}hFnpYj zZmwk0@#KjR=CmdTUX&W2@te0vf2c0AGK4`;_F!}H;z;l#CsX77+A%N-2Q zRQ+)hS(fD@_)BboQ^$kGr^nGbEiRXL(DqP5`C{5ET#Ed{{nZDT^=zo zA0L#?`cBi+vTR#W|1Q~Z$Kgz~Cj^M-I!T#}f0zKPbr<<_&|aIt+KOz08{~ z(h-#8z$`jZLU%k33EyMg9wujS*P!3+v5RsnyYK#?O|CR@s;a+rdn7pKyC6Y}m%TZO158(qVG}H-9&8KSBm^-W58R{(V}u zwz(POGpq{OVUcyvE8drWW0(rqtm8BV-K&~x8_lI5D+@3$BP^ExSV z3OXv_udh*QwuuJeL`M-;_6X8NgUDIdMd$gS4fF!Wq&OWN!t@}pB+yy0rZk0*<^k~B zk{&5YCycVMX=3V`p<-ouUdWGvYF*YY#_`B74&^l9WAcR^w7JHVpqWG0()U`I0{SIw ziu5O6J7g-H)il~G!01}irSEH6sPEOL*Zo6A4RnEWfZLfWzd~HKavQmsjo+x6YCBp- zu=JMW1JhGjqcfe~wY;>TN{v4Sj#D$rj+~xu2WnE)okKUTCvDBnX`wEPT+O^iT9f1c zN%aOQC!dsc_azPL!IL5p0tpjHMpg31?P&CHDIfVZyd5kS8Ub6klR^d1uoii0)=npF>K!N+ zZpKhsr>wcdrE$yFi$N~J9j9Z=k8*sdn)Ewv7osT}Ax$K?Xhafu+&T?G?B8_^U39xy zn3m1k%V{pN-yRwYR^si!F-joMxU?_7iNm3?Vs^ofGfhKv-uyw`+MJ_wUfdT9# z%3&SegQ;y2=Tb<+Fi^>i78|wv(xDmX96(&>OOD&5)!`lQX!wHLM#-+`It7A^=24J9 zU79Q-Ig_X`%k?Lbd54=jZ*s)J$SoF?uqD+&0@s&OLA4c8fB}|*ByqCjxCHo5M;(jQ z8)=n-35;#L2;{cc3*dptyX~tNS~8C0V-GIg2AVxXr){GdL6!bQkuf(=4eR)$g|Rvt zN{Ns@2EMP!l@VyRZNM8PLgmH@WXV>?79L|!TY5n<>R}22j%N(>`IO@jb=VT1KPh9Y zX0np9HxEi?oUHtl4{=m1U(~UdgbPp6W0?}_!do#S)Wf}}x0@5~c9N+hG2i8c@zpGl zqh1ccU>0#kc%&MwbaKWK%vs!>g)Og%eiQPGg0nxJ;8W}9nMED7Hh#7Pu)fuuS_}NVy&Am zK}&mII2mW^JcM!K$R8TJ6uo2r1+?+^y?(y``IpfD$TjNqub_Y6&#%VSwKnR>;?B6T z*Uv5D?)j?df4Zf>==q9*{M@QleqIgzy3_dkO6YyF{f}#)XZtIz*UQnrzN_W#E=B+N zzQdh+5&E^asC_;kJv*>m1N$8G&GWCrCG+p+tNj=9|8|M}3qq{dfR3)v(f|Me07*qo IM6N<$g3*&4T>t<8 literal 0 HcmV?d00001 diff --git a/seed.data/role.privileges.json b/seed.data/role.privileges.json index a626980..3e63a1e 100644 --- a/seed.data/role.privileges.json +++ b/seed.data/role.privileges.json @@ -25,7 +25,9 @@ "Client.Update", "Client.Delete", "Client.GetApiKey", - "Client.RenewApiKey" + "Client.RenewApiKey", + + "Badge.GetStockBadgeImages" ] }, { @@ -100,7 +102,9 @@ "Redemption.Delete", "Types.GetEventActionTypes", - "Types.GetRoles" + "Types.GetRoles", + + "Badge.GetStockBadgeImages" ] } ] diff --git a/src/api/awards/badge/badge.controller.ts b/src/api/awards/badge/badge.controller.ts index fcef290..4ef5a69 100644 --- a/src/api/awards/badge/badge.controller.ts +++ b/src/api/awards/badge/badge.controller.ts @@ -6,6 +6,7 @@ import { BadgeService } from '../../../database/services/awards/badge.service'; import { ErrorHandler } from '../../../common/handlers/error.handler'; import { BadgeCreateModel, BadgeSearchFilters, BadgeUpdateModel } from '../../../domain.types/awards/badge.domain.types'; import { uuid } from '../../../domain.types/miscellaneous/system.types'; +import { BadgeStockImageService } from '../../../database/services/badge.stock.images/badge.stock.image.service'; /////////////////////////////////////////////////////////////////////////////////////// @@ -15,6 +16,8 @@ export class BadgeController extends BaseController { _service: BadgeService = new BadgeService(); + _badgeStockservice: BadgeStockImageService = new BadgeStockImageService(); + _validator: BadgeValidator = new BadgeValidator(); constructor() { @@ -87,4 +90,18 @@ export class BadgeController extends BaseController { } }; + getStockBadgeImages = async (request: express.Request, response: express.Response): Promise => { + try { + await this.authorize('Badge.GetStockBadgeImages',request, response, false); + + const images = await this._badgeStockservice.getAll(); + const message = 'Badge stock images retrieved successfully!'; + + ResponseHandler.success(request, response, message, 200, images); + + } catch (error) { + ResponseHandler.handleError(request, response, error); + } + }; + } diff --git a/src/api/awards/badge/badge.routes.ts b/src/api/awards/badge/badge.routes.ts index 520660b..a112516 100644 --- a/src/api/awards/badge/badge.routes.ts +++ b/src/api/awards/badge/badge.routes.ts @@ -15,6 +15,7 @@ export const register = (app: express.Application): void => { const controller = new BadgeController(); router.post('/', authenticator.authenticateClient, authenticator.authenticateUser, controller.create); + router.get('/stock-images', authenticator.authenticateClient, controller.getStockBadgeImages); router.get('/search', authenticator.authenticateClient, authenticator.authenticateUser, controller.search); router.get('/:id', authenticator.authenticateClient, authenticator.authenticateUser, controller.getById); router.put('/:id', authenticator.authenticateClient, authenticator.authenticateUser, controller.update); diff --git a/src/api/awards/participant/participant.controller.ts b/src/api/awards/participant/participant.controller.ts index e597d6d..e90aec9 100644 --- a/src/api/awards/participant/participant.controller.ts +++ b/src/api/awards/participant/participant.controller.ts @@ -133,11 +133,7 @@ export class ParticipantController extends BaseController { const allBadges = await this._badgeService.getByClientId(clientId); const badges = this.classifyAllBadgesByCategory(allBadges); const classified = this.classifyParticipantBadges(participantBadges, badges); - - const result = { - BadgesByCategory: classified, - BadgeList: participantBadges, - }; + var result = await this._service.getBadgeImageUrl(participantBadges, classified); ResponseHandler.success(request, response, message, 200, result); } catch (error) { diff --git a/src/api/base.validator.ts b/src/api/base.validator.ts index 203d4f9..01e6891 100644 --- a/src/api/base.validator.ts +++ b/src/api/base.validator.ts @@ -4,6 +4,8 @@ import { ErrorHandler } from '../common/handlers/error.handler'; import { uuid } from '../domain.types/miscellaneous/system.types'; +import { DownloadDisposition } from '../domain.types/general/file.resource/file.resource.types'; +import { FileResourceMetadata } from '..//domain.types/general/file.resource/file.resource.types'; ////////////////////////////////////////////////////////////////// @@ -20,4 +22,33 @@ export default class BaseValidator { } }; + getByVersionName = async (request: express.Request): Promise => { + + var disposition = this.getDownloadDisposition(request); + + var metadata: FileResourceMetadata = { + ResourceId : request.params.id, + Version : request.params.version, + Disposition : disposition + }; + + return metadata; + }; + + public getDownloadDisposition(request) { + var disposition = DownloadDisposition.Auto; + if (request.query.disposition) { + if (request.query.disposition === 'inline') { + disposition = DownloadDisposition.Inline; + } + else if (request.query.disposition === 'stream') { + disposition = DownloadDisposition.Stream; + } + else { + disposition = DownloadDisposition.Attachment; + } + } + return disposition; + } + } diff --git a/src/api/general/file.resource/file.resource.controller.ts b/src/api/general/file.resource/file.resource.controller.ts index 3bf84d6..361080a 100644 --- a/src/api/general/file.resource/file.resource.controller.ts +++ b/src/api/general/file.resource/file.resource.controller.ts @@ -1,30 +1,42 @@ import express from 'express'; +import fs from 'fs'; import { ResponseHandler } from '../../../common/handlers/response.handler'; import { FileResourceService } from '../../../database/services/general/file.resource.service'; import { BaseController } from '../../base.controller'; import { uuid } from '../../../domain.types/miscellaneous/system.types'; -import { ErrorHandler } from '../../../common/handlers/error.handler'; +import { ApiError, ErrorHandler } from '../../../common/handlers/error.handler'; import BaseValidator from '../../base.validator'; import * as mime from 'mime-types'; import { FileResourceCreateModel } from '../../../domain.types/general/file.resource.domain.types'; import { FileUtils } from '../../../common/utilities/file.utils'; import { Loader } from '../../../startup/loader'; import { StorageService } from '../../../modules/storage/storage.service'; +import { IFileStorageService } from '../../../modules/storage/interfaces/file.storage.service.interface'; +import { FileResourceMetadata } from '../../../domain.types/general/file.resource/file.resource.types'; +import { Authenticator } from '../../../auth/authenticator'; +import path from 'path'; +import { Helper } from '../../../common/helper'; +import { DownloadDisposition } from '../../../domain.types/general/file.resource/file.resource.types'; /////////////////////////////////////////////////////////////////////////////////////// export class FileResourceController extends BaseController { //#region member variables and constructors + _service: FileResourceService = null; - _service: FileResourceService = new FileResourceService(); + _storageService: StorageService = Loader.Container.resolve(StorageService); _validator: BaseValidator = new BaseValidator(); - _storageService: StorageService = Loader.Container.resolve(StorageService); + _authenticator: Authenticator = null; + constructor() { super(); + this._service = new FileResourceService(); + this._authenticator = Loader.Authenticator; + } //#endregion @@ -95,7 +107,7 @@ export class FileResourceController extends BaseController { response.setHeader('Content-type', mimeType as string); this.setResponseHeaders(response, originalFilename, disposition); - var readStream = await this._storageService.download(storageKey); + var readStream = await this._storageService.download(storageKey, ''); if (!readStream) { ErrorHandler.throwInternalServerError(`Unable to download the file!`); } @@ -152,6 +164,79 @@ export class FileResourceController extends BaseController { else { response.setHeader('Content-disposition', 'attachment;filename=' + filename); } + }; + + downloadByVersionName = async (request: express.Request, response: express.Response): Promise => { + try { + request.context = 'FileResource.DownloadByVersionName'; + const metadata = await this._validator.getByVersionName(request); + var resource = await this._service.getById(metadata.ResourceId); + + if (resource.Public === false) { + + //NOTE: Please note that this is deviation from regular pattern of + //authentication middleware pipeline. Here we are authenticating client + //and user only when the file resource is not public. + + await this._authenticator.checkAuthentication(request); + await this._authorizer.authorize(request, response); + } + + console.log(`Download request for Resource Id:: ${metadata.ResourceId} + and Version:: ${metadata.Version}`); + const localDestination = await this._service.downloadByVersionName( + metadata.ResourceId, + metadata.Version); + + this.streamToResponse(localDestination, response, metadata); + + } catch (error) { + ResponseHandler.handleError(request, response, error); + } + }; + + private streamToResponse( + localDestination: string, + response: express.Response>, + metadata: FileResourceMetadata) { + + if (localDestination == null) { + throw new ApiError(404, 'File resource not found.'); + } + + var filename = path.basename(localDestination); + var mimetype = metadata.MimeType ?? Helper.getMimeType(localDestination); + if (!mimetype) { + mimetype = 'text/plain'; + } + + this.setDownloadResponseHeaders(response, metadata.Disposition, mimetype, filename); + + var filestream = fs.createReadStream(localDestination); + filestream.pipe(response); + }; + + private setDownloadResponseHeaders( + response: express.Response, + disposition: DownloadDisposition, + mimeType: string, + filename: string) { + + response.setHeader('Content-type', mimeType); + + if (disposition === DownloadDisposition.Attachment) { + response.setHeader('Content-disposition', 'attachment; filename=' + filename); + } + else if (disposition === DownloadDisposition.Inline || + (mimeType === 'image/jpeg' || + mimeType === 'image/png' || + mimeType === 'image/bmp')) { + response.setHeader('Content-disposition', 'inline'); + } + else { + response.setHeader('Content-disposition', 'attachment; filename=' + filename); + } + } //#endregion diff --git a/src/api/general/file.resource/file.resource.routes.ts b/src/api/general/file.resource/file.resource.routes.ts index 362c853..008da0c 100644 --- a/src/api/general/file.resource/file.resource.routes.ts +++ b/src/api/general/file.resource/file.resource.routes.ts @@ -15,5 +15,7 @@ export const register = (app: express.Application): void => { router.get('/:id', authenticator.authenticateUser, controller.getById); router.delete('/:id', authenticator.authenticateUser, controller.delete); + router.get('/:id/download-by-version-name/:version', controller.downloadByVersionName); + app.use('/api/v1/file-resources', router); }; diff --git a/src/common/helper.ts b/src/common/helper.ts index 2dcb1e9..c24575a 100644 --- a/src/common/helper.ts +++ b/src/common/helper.ts @@ -2,6 +2,7 @@ import child_process from 'child_process'; import { Gender } from '../domain.types/miscellaneous/system.types'; import Countries from './miscellaneous/country.codes'; import { TypeUtils } from './utilities/type.utils'; +import mime = require('mime-types'); //////////////////////////////////////////////////////////////////////// @@ -162,4 +163,12 @@ export class Helper { return possiblePhoneNumbers; }; + public static getMimeType = (pathOrExtension: string) => { + var mimeType = mime.lookup(pathOrExtension); + if (!mimeType) { + mimeType = 'text/plain'; + } + return mimeType; + }; + } diff --git a/src/database/database.connector.ts b/src/database/database.connector.ts index af27889..475b83e 100644 --- a/src/database/database.connector.ts +++ b/src/database/database.connector.ts @@ -32,6 +32,8 @@ import { Role } from "./models/user/role.model"; import { Privilege } from "./models/user/privilege.model"; import { SchemaEventType } from "./models/engine/schema.event.type.model"; import { DBLogger } from "./database.logger"; +import { FileResourceVersion } from "./models/general/file.resource.version.model"; +import { BadgeStockImage } from "./models/awards/badge.stock.image.model"; /////////////////////////////////////////////////////////////////////////////////// @@ -89,6 +91,8 @@ class DatabaseConnector { Role, Privilege, SchemaEventType, + FileResourceVersion, + BadgeStockImage, ], migrations : [], subscribers : [], diff --git a/src/database/mappers/awards/badge.stock.image.mapper.ts b/src/database/mappers/awards/badge.stock.image.mapper.ts new file mode 100644 index 0000000..e17272d --- /dev/null +++ b/src/database/mappers/awards/badge.stock.image.mapper.ts @@ -0,0 +1,23 @@ +import { BadgeStockImageDto } from '../../../domain.types/badge.stock.image/badge.stock.image.dto'; +import { BadgeStockImage } from '../../../database/models/awards/badge.stock.image.model'; + +/////////////////////////////////////////////////////////////////////////////////// + +export class BadgeStockImageMapper { + + static toResponseDto = (badgeStockImage: BadgeStockImage): BadgeStockImageDto => { + if (badgeStockImage == null) { + return null; + } + const dto: BadgeStockImageDto = { + id : badgeStockImage.id, + Code : badgeStockImage.Code, + FileName : badgeStockImage.FileName, + ResourceId : badgeStockImage.ResourceId, + PublicUrl : badgeStockImage.PublicUrl + + }; + return dto; + }; + +} diff --git a/src/database/mappers/general/file.resource.mapper.ts b/src/database/mappers/general/file.resource.mapper.ts index 1c6b4fd..1f2ad73 100644 --- a/src/database/mappers/general/file.resource.mapper.ts +++ b/src/database/mappers/general/file.resource.mapper.ts @@ -2,6 +2,9 @@ import { FileResource } from '../../models/general/file.resource.model'; import { FileResourceResponseDto, } from '../../../domain.types/general/file.resource.domain.types'; +import { FileResourceMetadata } from '../../../domain.types/general/file.resource/file.resource.types'; +import { ConfigurationManager } from '../../../config/configuration.manager'; +import { FileResourceVersion } from '../../../database/models/general/file.resource.version.model'; /////////////////////////////////////////////////////////////////////////////////// @@ -27,4 +30,32 @@ export class FileResourceMapper { return dto; }; + static toFileVersionDto = (fileVersion ?: FileResourceVersion, sanitize = false): FileResourceMetadata => { + + if (fileVersion == null){ + return null; + } + + var url = ConfigurationManager.BaseUrl + '/api/v1/file-resources/' + fileVersion.ResourceId + '/download-by-version-name/' + fileVersion.Version; + + var v: FileResourceMetadata = { + VersionId : fileVersion.id, + ResourceId : fileVersion.ResourceId, + Version : fileVersion.Version, + FileName : fileVersion.FileName, + MimeType : fileVersion.MimeType, + OriginalName : fileVersion.OriginalFileName, + Size : fileVersion.SizeInKB, + StorageKey : fileVersion.StorageKey, + Url : url + }; + + if (sanitize) { + v.StorageKey = null; + } + + return v; + }; + + } diff --git a/src/database/models/awards/badge.stock.image.model.ts b/src/database/models/awards/badge.stock.image.model.ts new file mode 100644 index 0000000..94f54a3 --- /dev/null +++ b/src/database/models/awards/badge.stock.image.model.ts @@ -0,0 +1,42 @@ +import { IsUUID } from "class-validator"; +import "reflect-metadata"; +import { + Column, + CreateDateColumn, + DeleteDateColumn, + Entity, + PrimaryGeneratedColumn, + UpdateDateColumn, +} from 'typeorm'; + +//////////////////////////////////////////////////////////////////////// + +@Entity({ name: 'badge_stock_images' }) +export class BadgeStockImage { + + @PrimaryGeneratedColumn() + id : number; + + @Column({ type: 'varchar', length: 64, nullable: true }) + Code : string; + + @Column({ type: 'varchar', length: 256, nullable: false }) + FileName : string; + + @Column({ type: 'uuid', nullable: true }) + @IsUUID() + ResourceId : string; + + @Column({ type: 'varchar', length: 2048, nullable: true }) + PublicUrl: string; + + @CreateDateColumn() + CreatedAt : Date; + + @UpdateDateColumn() + UpdatedAt : Date; + + @DeleteDateColumn() + DeletedAt : Date; + +} diff --git a/src/database/models/general/file.resource.model.ts b/src/database/models/general/file.resource.model.ts index f36d738..5fe6c6d 100644 --- a/src/database/models/general/file.resource.model.ts +++ b/src/database/models/general/file.resource.model.ts @@ -1,4 +1,5 @@ import "reflect-metadata"; +import { FileResourceMetadata } from "../../../domain.types/general/file.resource/file.resource.types"; import { Column, Entity, @@ -6,9 +7,11 @@ import { CreateDateColumn, UpdateDateColumn, DeleteDateColumn, + OneToOne, } from 'typeorm'; import { User } from './../user/user.model'; +import { FileResourceVersion } from "./file.resource.version.model"; //////////////////////////////////////////////////////////////////////// @@ -18,15 +21,26 @@ export class FileResource { @PrimaryGeneratedColumn('uuid') id : string; + @Column({ type: 'varchar', length: 1024, nullable: true }) + OriginalFilename : string; + @Column({ type: 'varchar', length: 1024, nullable: false }) StorageKey : string; - @Column({ type: 'varchar', length: 256, nullable: false }) - OriginalFilename : string; + @OneToOne(() => User) + @Column({ type: 'uuid', nullable: true }) + OwnerUserId : string; + + @OneToOne(() => User) + @Column({ type: 'uuid', nullable: true }) + UploadedByUserId : string; @Column({ type: 'varchar', length: 256, nullable: false }) MimeType : string; + @Column({ type: 'varchar', length: 256, nullable: true }) + Url : string; + @Column({ type: 'boolean', nullable: false, default: false }) Public : boolean; @@ -39,9 +53,15 @@ export class FileResource { @Column({ type: 'uuid', nullable: true }) UploadedBy : User; - @Column('simple-json') + @Column({ type: 'simple-json', nullable: true}) Tags : string[]; + @Column({ type: 'uuid', nullable : true }) + DefaultVersionId: string; + + @Column({ type: 'simple-json', nullable : true }) + DefaultVersion: any; + @CreateDateColumn() CreatedAt : Date; diff --git a/src/database/models/general/file.resource.version.model.ts b/src/database/models/general/file.resource.version.model.ts new file mode 100644 index 0000000..8f793ff --- /dev/null +++ b/src/database/models/general/file.resource.version.model.ts @@ -0,0 +1,53 @@ +import "reflect-metadata"; +import { + Column, + Entity, + PrimaryGeneratedColumn, + CreateDateColumn, + UpdateDateColumn, + DeleteDateColumn, + OneToOne, +} from 'typeorm'; + +import { FileResource } from "./file.resource.model"; + +//////////////////////////////////////////////////////////////////////// + +@Entity({ name: 'file_resource_versions' }) +export class FileResourceVersion { + + @PrimaryGeneratedColumn('uuid') + id : string; + + @OneToOne(() => FileResource) + @Column({ type: 'uuid'}) + ResourceId : string; + + @Column({ type: 'uuid', length: 256, nullable: true }) + FileName : string; + + @Column({ type: 'uuid', length: 256, nullable: true }) + OriginalFileName : string; + + @Column({ type: 'varchar', length: 32, nullable: true }) + Version : string; + + @Column({ type: 'varchar', length: 256, nullable: true }) + MimeType : string; + + @Column({ type: 'varchar', length: 512, nullable: true }) + StorageKey : string; + + @Column({ type: 'float', nullable: true }) + SizeInKB : number; + + @CreateDateColumn() + CreatedAt : Date; + + @UpdateDateColumn() + UpdatedAt : Date; + + @DeleteDateColumn() + DeletedAt : Date; + +} diff --git a/src/database/services/awards/participant.service.ts b/src/database/services/awards/participant.service.ts index 9e5cc49..d0ad7b6 100644 --- a/src/database/services/awards/participant.service.ts +++ b/src/database/services/awards/participant.service.ts @@ -13,6 +13,7 @@ import { uuid } from '../../../domain.types/miscellaneous/system.types'; import { StringUtils } from '../../../common/utilities/string.utils'; import { Context } from '../../models/engine/context.model'; import { ContextType } from '../../../domain.types/engine/engine.types'; +import { BadgeStockImage } from '../../../database/models/awards/badge.stock.image.model'; /////////////////////////////////////////////////////////////////////// @@ -30,6 +31,8 @@ export class ParticipantService extends BaseService { _badgeRepository: Repository = Source.getRepository(Badge); + _badgeStockImageRepository: Repository = Source.getRepository(BadgeStockImage); + //#endregion public create = async (createModel: ParticipantCreateModel) @@ -309,6 +312,7 @@ export class ParticipantService extends BaseService { // CreatedAt : true, // } }; + const list = await this._participantBadgeRepository.find(search); const participantBadges = list.map(x => { return { @@ -373,6 +377,27 @@ export class ParticipantService extends BaseService { return search; }; + + public getBadgeImageUrl =async (participantBadges: ParticipantBadgeResponseDto[], classified: any) => { + + var result = null; + for await (var participantBadge of participantBadges) { + var badgeimage = await this._badgeStockImageRepository.findOne({ + where : { + Code : participantBadge.Badge.Name + } + }); + participantBadge.Badge.ImageUrl = badgeimage.PublicUrl ? badgeimage.PublicUrl: null; + result = { + BadgesByCategory: classified, + BadgeList: participantBadges, + }; + + } + return result; + }; + + //#endregion } diff --git a/src/database/services/badge.stock.images/badge.stock.image.service.ts b/src/database/services/badge.stock.images/badge.stock.image.service.ts new file mode 100644 index 0000000..cafe680 --- /dev/null +++ b/src/database/services/badge.stock.images/badge.stock.image.service.ts @@ -0,0 +1,57 @@ +import { logger } from '../../../logger/logger'; +import { ApiError, ErrorHandler } from '../../../common/handlers/error.handler'; +import { Source } from '../../database.connector'; +import { Repository } from 'typeorm'; +import { BadgeStockImage } from '../../../database/models/awards/badge.stock.image.model'; +import { BadgeStockImageDomainModel } from '../../../domain.types/badge.stock.image/badge.stock.image.domain.model'; +import { BadgeStockImageDto } from '../../../domain.types/badge.stock.image/badge.stock.image.dto'; +import { BadgeStockImageMapper } from '../../../database/mappers/awards/badge.stock.image.mapper'; + +/////////////////////////////////////////////////////////////////////// + +export class BadgeStockImageService { + + //#region Repositories + + _badgeStockRepository: Repository = Source.getRepository(BadgeStockImage); + + //#endregion + + public create = async (createModel: BadgeStockImageDomainModel): Promise => { + try { + const badgeStockImages = this._badgeStockRepository.create({ + Code : createModel.Code, + FileName : createModel.FileName, + ResourceId : createModel.ResourceId, + PublicUrl : createModel.PublicUrl, + + }); + var record = await this._badgeStockRepository.save(badgeStockImages); + return BadgeStockImageMapper.toResponseDto(record); + } catch (error) { + logger.error(error.message); + ErrorHandler.throwInternalServerError(error.message, 500); + } + }; + + getAll = async (): Promise => { + try { + + const foundResults = await this._badgeStockRepository.find(); + + const dtos: BadgeStockImageDto[] = []; + for (const stockImage of foundResults) { + const dto = await BadgeStockImageMapper.toResponseDto(stockImage); + dtos.push(dto); + } + + return dtos; + + } catch (error) { + console.log(error.message); + throw new ApiError(500, error.message); + } + }; + //#endregion + +} diff --git a/src/database/services/general/file.resource.service.ts b/src/database/services/general/file.resource.service.ts index 3e0c2c1..0ad172c 100644 --- a/src/database/services/general/file.resource.service.ts +++ b/src/database/services/general/file.resource.service.ts @@ -1,3 +1,4 @@ +import fs from 'fs'; import { FileResource } from '../../models/general/file.resource.model'; import { User } from '../../models/user/user.model'; import { ErrorHandler } from '../../../common/handlers/error.handler'; @@ -12,6 +13,15 @@ import { FindManyOptions, Like, Repository } from 'typeorm'; import { FileResourceMapper } from '../../mappers/general/file.resource.mapper'; import { uuid } from '../../../domain.types/miscellaneous/system.types'; import { logger } from '../../../logger/logger'; +import { FileResourceDto } from '../../../domain.types/general/file.resource/file.resource.dto'; +import { FileResourceMetadata } from '../../../domain.types/general/file.resource/file.resource.types'; +import path from 'path'; +import { Helper } from '../../../common/helper'; +import { AWSS3FileStorageService } from '../../../modules/storage/providers/aws.s3.file.storage.service'; +import { FileResourceVersion } from '../../../database/models/general/file.resource.version.model'; +import { FileResourceUploadDomainModel } from '../../../domain.types/general/file.resource/file.resource.domain.model'; +import { ConfigurationManager } from '../../../config/configuration.manager'; +import { TimeUtils } from '../../../common/utilities/time.utils'; /////////////////////////////////////////////////////////////////////////////////////////////// @@ -19,8 +29,12 @@ export class FileResourceService { //#region Models + _storageService: AWSS3FileStorageService = new AWSS3FileStorageService(); + _fileResourceRepository : Repository = Source.getRepository(FileResource); + _fileResourceVersionRepository : Repository = Source.getRepository(FileResourceVersion); + _userRepository : Repository = Source.getRepository(User); //#endregion @@ -234,6 +248,122 @@ export class FileResourceService { } }; + uploadLocal = async ( + sourceLocation: string, + storageLocation: string, + isPublicResource: boolean + ): Promise => { + + var exists = fs.existsSync(sourceLocation); + if (!exists) { + console.log('Source file location does not exist!'); + } + + var storageKey:string = null; + var existingStorageKey = await this._storageService.exists(storageLocation); + if (existingStorageKey !== undefined && existingStorageKey !== null) { + storageKey = existingStorageKey; + } + else { + storageKey = await this._storageService.upload(sourceLocation, storageLocation); + } + + var stats = fs.statSync(sourceLocation); + var filename = path.basename(sourceLocation); + + var metadata: FileResourceMetadata = { + Version : '1', + OriginalName : filename, + FileName : filename, + SourceFilePath : null, + MimeType : Helper.getMimeType(sourceLocation), + Size : stats['size'] / 1024, + StorageKey : storageKey, + }; + + + var domainModel: FileResourceUploadDomainModel = { + FileMetadata : metadata, + StorageKey : metadata.StorageKey, + FileName : metadata.FileName, + IsMultiResolutionImage : false, + MimeType : Helper.getMimeType(sourceLocation), + IsPublicResource : isPublicResource, + }; + + var resource = await this._fileResourceRepository.create(domainModel); + var record = await this._fileResourceRepository.save(resource); + + domainModel.FileMetadata.ResourceId = record.id; + var version = await this.addVersion(domainModel.FileMetadata, true); + resource.DefaultVersion = version; + resource.Url = version.Url; + + return resource; + }; + + addVersion = async (metadata: FileResourceMetadata, makeDefaultVersion: boolean): Promise => { + + var fileVersion = { + ResourceId : metadata.ResourceId, + Version : metadata.Version, + FileName : metadata.FileName, + OriginalFileName : metadata.OriginalName, + MimeType : metadata.MimeType, + StorageKey : metadata.StorageKey, + SizeInKB : metadata.Size, + }; + + var record = await this._fileResourceVersionRepository.create(fileVersion); + var version = await this._fileResourceVersionRepository.save(record); + + if (version === null) { + throw new Error('Unable to create version instance in database!'); + } + + if (makeDefaultVersion) { + var resource = await this._fileResourceRepository.findOne({ + where : { + id : metadata.ResourceId + } + }); + if (resource === null) { + throw new Error('Unable to find resource!'); + } + resource.DefaultVersionId = version.id; + //await resource.save(); + } + + return FileResourceMapper.toFileVersionDto(version); + }; + + downloadByVersionName = async (resourceId: string, versionName: string): Promise => { + var downloadFolderPath = await this.generateDownloadFolderPath(); + //var versionMetadata = await this._fileResourceRepo.getVersionByVersionName(resourceId, versionName); + + var versionMetadata = await this._fileResourceVersionRepository.findOne({ + where : { + ResourceId : resourceId, + } + }); + // const versionMetadata_ = FileResourceMapper.toFileVersionDto(versionMetadata); + var localFilePath = path.join(downloadFolderPath, versionMetadata.FileName); + var localDestination = await this._storageService.download(versionMetadata.StorageKey, localFilePath); + return localDestination; + }; + + private generateDownloadFolderPath = async() => { + + var timestamp = TimeUtils.timestamp(new Date()); + var tempDownloadFolder = ConfigurationManager.DownloadTemporaryFolder; + var downloadFolderPath = path.join(tempDownloadFolder, timestamp); + + //Make sure the path exists + await fs.promises.mkdir(downloadFolderPath, { recursive: true }); + + return downloadFolderPath; + }; + //#endregion } diff --git a/src/domain.types/badge.stock.image/badge.stock.image.domain.model.ts b/src/domain.types/badge.stock.image/badge.stock.image.domain.model.ts new file mode 100644 index 0000000..da4bcd4 --- /dev/null +++ b/src/domain.types/badge.stock.image/badge.stock.image.domain.model.ts @@ -0,0 +1,7 @@ +export interface BadgeStockImageDomainModel { + id? : number; + Code? : string; + FileName? : string; + ResourceId : string; + PublicUrl? : string; +} diff --git a/src/domain.types/badge.stock.image/badge.stock.image.dto.ts b/src/domain.types/badge.stock.image/badge.stock.image.dto.ts new file mode 100644 index 0000000..922e392 --- /dev/null +++ b/src/domain.types/badge.stock.image/badge.stock.image.dto.ts @@ -0,0 +1,7 @@ +export interface BadgeStockImageDto { + id? : number; + Code? : string; + FileName? : string; + ResourceId : string; + PublicUrl? : string; +} diff --git a/src/domain.types/general/file.resource.domain.types.ts b/src/domain.types/general/file.resource.domain.types.ts index cb1d68f..79ed8f8 100644 --- a/src/domain.types/general/file.resource.domain.types.ts +++ b/src/domain.types/general/file.resource.domain.types.ts @@ -4,6 +4,7 @@ import { uuid } from "../miscellaneous/system.types"; export interface FileResourceCreateModel { StorageKey ?: string; MimeType ?: string; + Metadata ?: any; OriginalFilename ?: string; UserId ?: uuid; Size ?: number; diff --git a/src/domain.types/general/file.resource/file.resource.domain.model.ts b/src/domain.types/general/file.resource/file.resource.domain.model.ts new file mode 100644 index 0000000..c9274c3 --- /dev/null +++ b/src/domain.types/general/file.resource/file.resource.domain.model.ts @@ -0,0 +1,26 @@ +import { FileResourceMetadata, ResourceReference } from "./file.resource.types"; + +export interface FileResourceUploadDomainModel { + FileMetadata : FileResourceMetadata; + OwnerUserId? : string; + UploadedByUserId? : string; + IsPublicResource? : boolean; + IsMultiResolutionImage? : boolean; + MimeType? : string; + DefaultVersionId? : string; + StorageKey? : string; + FileName? : string; +} + +export interface FileResourceRenameDomainModel { + id? : string, + NewFileName : string; +} + +export interface FileResourceUpdateModel { + FileMetadata? : FileResourceMetadata; + ResourceId : string; + References? : ResourceReference[]; + Tags? : string[]; + IsMultiResolutionImage? : boolean; +} diff --git a/src/domain.types/general/file.resource/file.resource.dto.ts b/src/domain.types/general/file.resource/file.resource.dto.ts new file mode 100644 index 0000000..073c855 --- /dev/null +++ b/src/domain.types/general/file.resource/file.resource.dto.ts @@ -0,0 +1,25 @@ +import { FileResourceMetadata, ResourceReference } from "./file.resource.types"; + +export interface FileResourceDetailsDto { + id? : string; + FileName? : string; + Url? : string; + OwnerUserId? : string; + UploadedByUserId? : string; + IsPublicResource? : boolean; + MimeType? : string; + DefaultVersion? : FileResourceMetadata; + Versions? : FileResourceMetadata[]; + References? : ResourceReference[]; + Tags? : string[]; +} + +export interface FileResourceDto { + id? : string; + FileName? : string; + Url? : string; + OwnerUserId? : string; + IsPublicResource? : boolean; + MimeType? : string; + DefaultVersion? : any; +} diff --git a/src/domain.types/general/file.resource/file.resource.search.types.ts b/src/domain.types/general/file.resource/file.resource.search.types.ts new file mode 100644 index 0000000..a2cd044 --- /dev/null +++ b/src/domain.types/general/file.resource/file.resource.search.types.ts @@ -0,0 +1,29 @@ +import { FileResourceDto } from "./file.resource.dto"; + +////////////////////////////////////////////////////////////////////// + +export interface FileResourceSearchFilters { + OwnerUserId? : string, + UploadedByUserId? : string, + IsPublicResource? : boolean; + ReferenceId? : string; + ReferenceType? : string; + ReferenceKeyword? : string; + Tag? : string; + CreatedDateFrom? : Date; + CreatedDateTo? : Date; + OrderBy? : string; + Order? : string; + PageIndex? : number; + ItemsPerPage? : number; +} + +export interface FileResourceSearchResults { + TotalCount : number; + RetrievedCount : number; + PageIndex : number; + ItemsPerPage : number; + Order : string; + OrderedBy : string; + Items : FileResourceDto[]; +} diff --git a/src/domain.types/general/file.resource/file.resource.types.ts b/src/domain.types/general/file.resource/file.resource.types.ts new file mode 100644 index 0000000..60bed84 --- /dev/null +++ b/src/domain.types/general/file.resource/file.resource.types.ts @@ -0,0 +1,31 @@ +import { Stream } from "stream"; + +export interface ResourceReference { + ItemId : string; + ItemType : string; + Keyword : string; +} + +export enum DownloadDisposition { + Inline = 'inline', + Attachment = 'attachment', + Stream = 'stream', + Auto = 'auto', +} + +export interface FileResourceMetadata { + ResourceId? : string; + VersionId? : string; + Version? : string; + FileName? : string; + OriginalName? : string; + SourceFilePath? : string; + MimeType? : string; + Size? : number; + StorageKey? : string; + IsDefaultVersion? : boolean; + IsPublicResource? : boolean; + Disposition? : DownloadDisposition; + Url? : string; + Stream? : Stream; +} diff --git a/src/modules/storage/interfaces/file.storage.service.interface.ts b/src/modules/storage/interfaces/file.storage.service.interface.ts index 82c7afa..3c49e46 100644 --- a/src/modules/storage/interfaces/file.storage.service.interface.ts +++ b/src/modules/storage/interfaces/file.storage.service.interface.ts @@ -5,7 +5,7 @@ export interface IFileStorageService { upload(inputStream, storageKey: string): Promise; - download(storageKey: string): Promise; + download(storageKey: string, localFilePath: string): Promise; uploadLocally(storageKey: string, localFilePath?: string): Promise; diff --git a/src/modules/storage/providers/aws.s3.file.storage.service.ts b/src/modules/storage/providers/aws.s3.file.storage.service.ts index f6ddde8..4988886 100644 --- a/src/modules/storage/providers/aws.s3.file.storage.service.ts +++ b/src/modules/storage/providers/aws.s3.file.storage.service.ts @@ -67,7 +67,7 @@ export class AWSS3FileStorageService implements IFileStorageService { } }; - download = async (storageKey: string): Promise => { + download = async (storageKey: string, localFilePath?: string): Promise => { try { const s3 = this.getS3Client(); const params = { diff --git a/src/modules/storage/storage.service.ts b/src/modules/storage/storage.service.ts index 63926b4..aae9a2a 100644 --- a/src/modules/storage/storage.service.ts +++ b/src/modules/storage/storage.service.ts @@ -16,15 +16,15 @@ export class StorageService { return await this._storageService.upload(inputStream, storageKey); } - download = async (storageKey: string): Promise => { - return await this._storageService.download(storageKey); + download = async (storageKey: string, localFilePath?: string): Promise => { + return await this._storageService.download(storageKey, localFilePath); } uploadLocally = async (storageKey: string, localFilePath?: string): Promise => { return await this._storageService.uploadLocally(storageKey, localFilePath); } - downloadLocally = async (storageKey: string, localFilePath: string): Promise => { + downloadLocally = async (storageKey: string, localFilePath?: string): Promise => { return await this._storageService.downloadLocally(storageKey, localFilePath); } diff --git a/src/startup/router.ts b/src/startup/router.ts index 2b8c814..96c0f01 100644 --- a/src/startup/router.ts +++ b/src/startup/router.ts @@ -14,6 +14,8 @@ import { register as registerIncomingEventRoutes } from '../api/engine/incoming. import { register as registerIncomingEventTypeRoutes } from '../api/engine/incoming.event.type/incoming.event.type.routes'; import { register as registerSchemaInstanceRoutes } from '../api/engine/schema.instance/schema.instance.routes'; import { register as registerTypesRoutes } from '../api/types/types.routes'; +import { register as registerFileResourceRoutes } from '../api/general/file.resource/file.resource.routes'; + //////////////////////////////////////////////////////////////////////////////////// @@ -50,6 +52,7 @@ export class Router { registerIncomingEventRoutes(this._app); registerSchemaInstanceRoutes(this._app); registerTypesRoutes(this._app); + registerFileResourceRoutes(this._app); resolve(true); diff --git a/src/startup/seeder.ts b/src/startup/seeder.ts index f923427..50a8e65 100644 --- a/src/startup/seeder.ts +++ b/src/startup/seeder.ts @@ -1,10 +1,8 @@ import fs from "fs"; import path from "path"; -import { Helper } from "../common/helper"; import { logger } from "../logger/logger"; import * as RolePrivilegesList from '../../seed.data/role.privileges.json'; import { UserService } from '../database/services/user/user.service'; -import { ClientService } from '../database/services/client/client.service'; import { UserCreateModel } from "../domain.types/user/user.domain.types"; import { Gender } from "../domain.types/miscellaneous/system.types"; import { RoleService } from "../database/services/user/role.service"; @@ -14,6 +12,10 @@ import { RoleCreateModel } from "../domain.types/user/role.domain.types"; import { ClientResponseDto } from "../domain.types/client/client.domain.types"; import { FileUtils } from "../common/utilities/file.utils"; import { StringUtils } from "../common/utilities/string.utils"; +import { BadgeStockImageDomainModel } from "../domain.types/badge.stock.image/badge.stock.image.domain.model"; +import { BadgeStockImageService } from "../database/services/badge.stock.images/badge.stock.image.service"; +import { ClientService } from "../database/services/client/client.service"; +import { Loader } from "./loader"; ////////////////////////////////////////////////////////////////////////////// @@ -29,6 +31,15 @@ export class Seeder { _fileResourceService: FileResourceService = null; + _badgeStockImageService: BadgeStockImageService = new BadgeStockImageService(); + + constructor () { + + this._fileResourceService = Loader.Container.resolve(FileResourceService); + + } + + public seed = async (): Promise => { try { await this.createTempFolders(); @@ -36,6 +47,7 @@ export class Seeder { const clients = await this.seedInternalClients(); await this.seedRolePrivileges(); await this.seedDefaultUsers(clients); + await this.seedBadgeStockImages(); } catch (error) { logger.error(error.message); } @@ -182,4 +194,42 @@ export class Seeder { logger.info('Seeded default roles successfully!'); }; + private seedBadgeStockImages = async () => { + + var images = await this._badgeStockImageService.getAll(); + if (images.length > 0) { + return; + } + + var cloudStoragePath = 'assets/images/stock.badge.images/'; + var sourceFilePath = path.join(process.cwd(), "./assets/images/stock.badge.images/"); + var files = fs.readdirSync(sourceFilePath); + var imageFiles = files.filter((f) => { + return path.extname(f).toLowerCase() === '.png'; + }); + + for await (const fileName of imageFiles) { + + var sourceFileLocation = path.join(sourceFilePath, fileName); + var storageFileLocation = cloudStoragePath + fileName; + + var uploaded = await this._fileResourceService.uploadLocal( + sourceFileLocation, + storageFileLocation, + true); + + var domainModel: BadgeStockImageDomainModel = { + Code : fileName.replace('.png', ''), + FileName : fileName, + ResourceId : uploaded.id, + PublicUrl : uploaded.DefaultVersion.Url + }; + + var badgeStockImage = await this._badgeStockImageService.create(domainModel); + if (!badgeStockImage) { + console.log('Error occurred while seeding medication stock images!'); + } + } + }; + } From d193bb950d611a35091f31e654f8bc5e8513954e Mon Sep 17 00:00:00 2001 From: vinay-debug <84920398+vinay-debug@users.noreply.github.com> Date: Fri, 2 Jun 2023 08:36:54 +0530 Subject: [PATCH 23/66] vital award pipeline --- .../fact.extractors/facts.db.connector.ts | 2 + .../models/vital.fact.model.ts | 41 +++++++++ .../data.extractors/data.extractor.ts | 4 + .../data.extractors/vital.data.extractor.ts | 84 +++++++++++++++++++ 4 files changed, 131 insertions(+) create mode 100644 src/modules/fact.extractors/models/vital.fact.model.ts create mode 100644 src/modules/processor/providers/implementation/data.extractors/vital.data.extractor.ts diff --git a/src/modules/fact.extractors/facts.db.connector.ts b/src/modules/fact.extractors/facts.db.connector.ts index c9338c7..5237f5c 100644 --- a/src/modules/fact.extractors/facts.db.connector.ts +++ b/src/modules/fact.extractors/facts.db.connector.ts @@ -8,6 +8,7 @@ import { MedicationFact } from './models/medication.fact.model'; import { DBLogger } from "./../../database/database.logger"; import { NutritionChoiceFact } from "./models/nutrition.choice.fact.model"; import { ExercisePhysicalActivityFact } from "./models/exercise.physical.activity.fact.model"; +import { VitalFact } from "./models/vital.fact.model"; /////////////////////////////////////////////////////////////////////////////////// const DATABASE_NAME = `awards_facts`; @@ -30,6 +31,7 @@ class FactsDatabaseConnector { BadgeFact, NutritionChoiceFact, ExercisePhysicalActivityFact, + VitalFact ], migrations : [], subscribers : [], diff --git a/src/modules/fact.extractors/models/vital.fact.model.ts b/src/modules/fact.extractors/models/vital.fact.model.ts new file mode 100644 index 0000000..36123ad --- /dev/null +++ b/src/modules/fact.extractors/models/vital.fact.model.ts @@ -0,0 +1,41 @@ +import { float } from "aws-sdk/clients/cloudfront"; +import "reflect-metadata"; +import { + Column, + Entity, + PrimaryGeneratedColumn, +} from 'typeorm'; + +//////////////////////////////////////////////////////////////////////// + +@Entity({ name: 'vital_facts' }) +export class VitalFact { + + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column({ type: 'uuid', nullable: false }) + ContextReferenceId: string; + + @Column({ type: 'uuid', nullable: true }) + RecordId: string; + + @Column({ type: 'varchar', length: 256, nullable: true }) + VitalName: string; + + @Column({ nullable: true, default: null }) + VitalPrimaryValue: float; + + @Column({ nullable: true, default: null }) + VitalSecondaryValue: float; + + @Column({ type: 'varchar', length: 16, nullable: true }) + Unit: string; + + @Column({ nullable: true }) + RecordDate: Date; + + @Column({ nullable: true }) + RecordDateStr: string; + +} diff --git a/src/modules/processor/providers/implementation/data.extractors/data.extractor.ts b/src/modules/processor/providers/implementation/data.extractors/data.extractor.ts index b18b0e7..277fa0a 100644 --- a/src/modules/processor/providers/implementation/data.extractors/data.extractor.ts +++ b/src/modules/processor/providers/implementation/data.extractors/data.extractor.ts @@ -10,6 +10,7 @@ import { MedicationDataExtractor } from './medication.data.extractor'; import { BadgeDataExtractor } from "./badge.data.extractor"; import { NutritionDataExtractor } from "./nutrition.data.extractor"; import { ExercisePhysicalActivityDataExtractor } from "./exercise.physical.activity.data.extractor"; +import { VitalDataExtractor } from "./vital.data.extractor"; ////////////////////////////////////////////////////////////////////// @@ -65,6 +66,9 @@ export class DataExtractor implements IDataExtractor { else if (recordType === 'Exercise') { return new ExercisePhysicalActivityDataExtractor(); } + else if (recordType === 'Vital') { + return new VitalDataExtractor(); + } return null; }; diff --git a/src/modules/processor/providers/implementation/data.extractors/vital.data.extractor.ts b/src/modules/processor/providers/implementation/data.extractors/vital.data.extractor.ts new file mode 100644 index 0000000..ffec3a2 --- /dev/null +++ b/src/modules/processor/providers/implementation/data.extractors/vital.data.extractor.ts @@ -0,0 +1,84 @@ +import { Repository } from "typeorm"; +import { FactsSource } from '../../../../fact.extractors/facts.db.connector'; +import { Context } from "../../../../../database/models/engine/context.model"; +import { DataExtractionInputParams, DataSamplingMethod, OutputParams, ProcessorResult } from '../../../../../domain.types/engine/engine.types'; +import { IExtractor } from "./extractor.interface"; +import { VitalFact } from "../../../../../modules/fact.extractors/models/vital.fact.model"; + +////////////////////////////////////////////////////////////////////// + +export class VitalDataExtractor implements IExtractor { + + //#region Repositories + + _vitalFactRepository: Repository = + FactsSource.getRepository(VitalFact); + + //#endregion + + public extract = async ( + context: Context, + inputParams: DataExtractionInputParams, + outputParams: OutputParams) => { + + const filters = inputParams.Filters ?? {}; + var samplingMethod = filters['SamplingMethod'] as DataSamplingMethod; + if (!samplingMethod) { + samplingMethod = DataSamplingMethod.Any; + } + + const records = await this._vitalFactRepository.find({ + where : { + ContextReferenceId : context.ReferenceId + }, + }); + + const groupedRecords = records.reduce((acc, obj) => { + const key = obj.RecordDateStr; + if (!acc[key]) { + acc[key] = []; + } + acc[key].push(obj); + return acc; + }, {}); + + const dayStats: { Day: string; Passed: boolean;}[] = []; + if (samplingMethod === DataSamplingMethod.Any) { + for (var grKey of Object.keys(groupedRecords)) { + const arr = groupedRecords[grKey]; + const passed = arr.some(obj => obj.VitalPrimaryValue !== null); // Check only for one record per day + dayStats.push({ + Day : grKey, + Passed : passed, + }); + } + } + else { + for (var grKey of Object.keys(groupedRecords)) { + const arr = groupedRecords[grKey]; + const passed = arr.every(obj => obj.VitalPrimaryValue !== null); // Check all records for the day + dayStats.push({ + Day : grKey, + Passed : passed, + }); + } + } + + const sorted = dayStats.sort((a, b) => Date.parse(a.Day) - Date.parse(b.Day)); + const transformed = sorted.map(x => { + return { + key : new Date(x.Day), + value : x.Passed, + }; + }); + + const result: ProcessorResult = { + Success : true, + Tag : outputParams.OutputTag, + Data : transformed + }; + + return result; + }; + +} From c72eab00b06fe03903e693bdbe982739259d9a47 Mon Sep 17 00:00:00 2001 From: tabbasum-rean Date: Mon, 5 Jun 2023 18:53:40 +0530 Subject: [PATCH 24/66] Mental health badge pipeline --- .../awards service.postman_collection.json | 3752 ++++++++++++++++- .../fact.extractors/facts.db.connector.ts | 2 + .../models/mental.health.fact.model.ts | 37 + .../data.extractors/data.extractor.ts | 4 + .../mental.health.data.extractor.ts | 83 + 5 files changed, 3694 insertions(+), 184 deletions(-) create mode 100644 src/modules/fact.extractors/models/mental.health.fact.model.ts create mode 100644 src/modules/processor/providers/implementation/data.extractors/mental.health.data.extractor.ts diff --git a/postman/awards service.postman_collection.json b/postman/awards service.postman_collection.json index c3aac99..e9d3ebf 100644 --- a/postman/awards service.postman_collection.json +++ b/postman/awards service.postman_collection.json @@ -1,9 +1,9 @@ { "info": { - "_postman_id": "d38423ff-1dbb-43c9-99a2-3c23bc63590e", - "name": "Awards service", + "_postman_id": "63f55a97-bf14-43c3-9534-b003676b8abd", + "name": "Awards service Copy", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "15905052" + "_exporter_id": "11713506" }, "item": [ { @@ -816,6 +816,84 @@ "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." }, "response": [] + }, + { + "name": "Create mental health event type", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"MENTAL_HEALTH_EVENT_TYPE_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Event type is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data.Name).to.not.be.null;\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Name\": \"MentalHealth\",\r\n \"Description\": \"This event is triggered when a patient marks medication consumption as taken or missed\"\r\n}\r\n" + }, + "url": { + "raw": "{{BASE_URL}}/engine/event-types", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "event-types" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] } ] }, @@ -11935,189 +12013,3409 @@ ] } ] - } - ] - } - ] - }, - { - "name": "Get context for participant / reference id", - "item": [ - { - "name": "Get schema instance by id", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "try {\r", - " var jsonRes = pm.response.json();\r", - " pm.environment.set(\"SCHEMA_INSTANCE_ID\", jsonRes.Data.id);\r", - "}\r", - "catch (error) {\r", - " console.log(error.message);\r", - "}\r", - "\r", - "pm.test(\"Request is successfull\", function () {\r", - " pm.response.to.have.status(200);\r", - " var jsonRes = pm.response.json();\r", - " pm.expect(jsonRes.Status).to.eql('success');\r", - "});\r", - "\r", - "pm.test(\"Schema instance is returned\", function () {\r", - " var jsonRes = pm.response.json();\r", - " pm.expect(jsonRes.Data).to.have.property('id');\r", - " pm.expect(jsonRes.Data).to.have.property('Client');\r", - " pm.expect(jsonRes.Data.Client).to.have.property('id');\r", - " pm.expect(jsonRes.Data).to.have.property('Name');\r", - " pm.expect(jsonRes.Data).to.have.property('Description');\r", - " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", - " pm.expect(jsonRes.Data).to.have.property('RootNodeId');\r", - "});\r", - "" - ], - "type": "text/javascript" - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "" - ], - "type": "text/javascript" - } - } - ], - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [ - { - "key": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "x-api-key", - "value": "{{API_KEY}}", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Medication 7 Day Badge Rule\",\r\n \"Description\": \"This rule represents logical steps involved in awarding a badge for consecutive 7 days.\",\r\n \"ParentNodeId\": \"{{SCHEMA_ROOT_NODE_ID}}\",\r\n \"Action\": {\r\n \"ActionType\": \"{{AWARD_BADGE_EVENT_TYPE}}\",\r\n \"Name\": \"Medication 7-Days Badge\",\r\n \"Description\": \"This rule represents logical steps involved in awarding a badge for consecutive 7 days.\",\r\n \"Params\": {\r\n \"Message\": \"Award medication 7-days badge.\",\r\n \"Action\": \"{{AWARD_BADGE_EVENT_TYPE}}\",\r\n \"NextNodeId\": null,\r\n \"Extra\": {}\r\n }\r\n }\r\n}" - }, - "url": { - "raw": "{{BASE_URL}}/engine/schema-instances/{{SCHEMA_INSTANCE_ID}}", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "engine", - "schema-instances", - "{{SCHEMA_INSTANCE_ID}}" - ] - }, - "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." - }, - "response": [] - } - ] - }, - { - "name": "Get participant badges", - "item": [ - { - "name": "Get participant by reference id", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "try {\r", - " var jsonRes = pm.response.json();\r", - " pm.environment.set(\"PARTICIPANT_ID\", jsonRes.Data.id);\r", - "}\r", - "catch (error) {\r", - " console.log(error.message);\r", - "}\r", - "\r", - "pm.test(\"Request is successfull\", function () {\r", - " pm.response.to.have.status(200);\r", - " var jsonRes = pm.response.json();\r", - " pm.expect(jsonRes.Status).to.eql('success');\r", - "});\r", - "\r", - "pm.test(\"Schema instance is returned\", function () {\r", - " var jsonRes = pm.response.json();\r", - " pm.expect(jsonRes.Data).to.have.property('id');\r", - " pm.expect(jsonRes.Data).to.have.property('Client');\r", - " pm.expect(jsonRes.Data.Client).to.have.property('id');\r", - " pm.expect(jsonRes.Data).to.have.property('Name');\r", - " pm.expect(jsonRes.Data).to.have.property('Description');\r", - " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", - " pm.expect(jsonRes.Data).to.have.property('RootNodeId');\r", - "});\r", - "" - ], - "type": "text/javascript" - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "" - ], - "type": "text/javascript" - } - } - ], - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [ - { - "key": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "x-api-key", - "value": "{{API_KEY}}", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "" - }, - "url": { - "raw": "{{BASE_URL}}/participants/by-reference-id/{{REFERENCE_ID}}", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "participants", - "by-reference-id", - "{{REFERENCE_ID}}" - ] }, - "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." - }, - "response": [] - }, - { - "name": "Get participant badges", - "event": [ { - "listen": "test", - "script": { + "name": "mental health badges", + "item": [ + { + "name": "Create badge category", + "item": [ + { + "name": "Create badge category", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"BADGE_CATEGORY_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Participant is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"MentalHealth\",\r\n \"Description\": \"Badge category for mental health related badges\",\r\n \"ImageUrl\": \"https://e7.pngegg.com/pngimages/626/893/png-clipart-blue-and-white-check-logo-facebook-social-media-verified-badge-logo-vanity-url-blue-checkmark-blue-angle.png\"\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/badge-categories", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badge-categories" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get badge category by id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/badge-categories/{{BADGE_CATEGORY_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badge-categories", + "{{BADGE_CATEGORY_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + }, + { + "name": "Schema-7-Day mental health badge", + "item": [ + { + "name": "Create badge", + "item": [ + { + "name": "Create badge", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"BADGE_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Participant is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + "\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"CategoryId\": \"{{BADGE_CATEGORY_ID}}\",\r\n \"Name\": \"Mental health 7-Day Badge\",\r\n \"Description\": \"Badge awarded choosing mental health for 7-days consistently.\",\r\n \"ImageUrl\": \"https://e7.pngegg.com/pngimages/626/893/png-clipart-blue-and-white-check-logo-facebook-social-media-verified-badge-logo-vanity-url-blue-checkmark-blue-angle.png\"\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/badges", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badges" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get badge by id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/badges/{{BADGE_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badges", + "{{BADGE_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + }, + { + "name": "Create schema", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"SCHEMA_ID\", jsonRes.Data.id);\r", + " pm.environment.set(\"SCHEMA_ROOT_NODE_ID\", jsonRes.Data.RootNode.id);\r", + " pm.environment.set(\"NODE_01_ID\", jsonRes.Data.RootNode.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Client');\r", + " pm.expect(jsonRes.Data.Client).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", + " pm.expect(jsonRes.Data).to.have.property('RootNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Nutrition 7-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient takes chooses mental health monitoring for 7 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{MENTAL_HEALTH_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract mental health data\",\r\n \"Description\": \"Extract mental health data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract mental health data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"MentalHealth\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"Any\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting mental health data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:MentalHealth\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/schema", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "schema" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "01 - Get root Node - Extract mental health data", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_01_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is retrieved\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_01_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_01_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "02 - Create next node - Calculate Continuity", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_02_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_01_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Calculate continuity\",\r\n \"Description\": \"This execution step involves calculating the continuity for mental health monitoring consecutively for 7-days.\",\r\n \"Action\": {\r\n \"ActionType\": \"Process-Data\",\r\n \"Name\": \"Calculate Continuity\",\r\n \"InputParams\": {\r\n \"RecordType\": \"MentalHealth\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Extract-Data:MentalHealth\",\r\n \"DataActionType\": \"Calculate-Continuity\",\r\n \"KeyDataType\": \"Date\",\r\n \"KeyName\": \"Date\",\r\n \"ValueDataType\": \"Float\",\r\n \"ValueName\": \"Duration\",\r\n \"Operator\": \"Exists\",\r\n \"ContinuityCount\": 7\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Processing records for 7-day mental health continuity\",\r\n \"OutputTag\": \"Calculate-Continuity:MentalHealth\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 01", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_02_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_01_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_01_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "03 - Create next node - Extract existing badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_03_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_02_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Get existing badges\",\r\n \"Description\": \"Extract existing 7-day mental health monitoring badges for the participant.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract-Badges\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Database\",\r\n \"InputTag\": \"Badge\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"MentalHealth\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"Mental health 7-Day Badge\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting 7-day 7-Day mental health badges\",\r\n \"OutputTag\": \"Extract-Data:Badge\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 02", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_03_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_02_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_02_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "04 - Create next node - Compare badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_04_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_03_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Compare badges\",\r\n \"Description\": \"Compare calculated badges against existing badges for 7-day mental health monitoring.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Compare-Data\",\r\n \"Name\": \"Compare badges\",\r\n \"Description\": \"Compare calculated badges against existing badges for 7-day mental health monitoring\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Calculate-Continuity:MentalHealth\",\r\n \"SecondaryInputTag\": \"Extract-Data:Badge\",\r\n \"DataActionType\": \"Find-Range-Difference\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"MentalHealth\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"Mental health 7-Day Badge\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Comparing badges and get updated badge list for 7-Day mental health monitoring badges.\",\r\n \"OutputTag\": \"Compare-Data:Badge\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 03", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_04_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_03_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_03_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "05 - Create next node - Store updated badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_05_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_04_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Store updated badges\",\r\n \"Description\": \"Store updated 7-day mental health monitoring badges for the participant.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Store-Data\",\r\n \"Name\": \"Store updated badges\",\r\n \"Description\": \"Store updated 7-day mental health monitoring badges for the participant.\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Compare-Data:Badge\",\r\n \"StorageKeys\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"MentalHealth\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"Mental health 7-Day Badge\"\r\n },\r\n {\r\n \"Key\": \"BadgeId\",\r\n \"Value\": \"{{BADGE_ID}}\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting 7-day mental health monitoring badges\",\r\n \"OutputTag\": \"Store-Data:Badge\",\r\n \"DestinationType\": \"Database\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 04", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_05_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_04_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_04_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get schema by Id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Client');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", + " pm.expect(jsonRes.Data).to.have.property('RootNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/engine/schema/{{SCHEMA_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "schema", + "{{SCHEMA_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + }, + { + "name": "Schema-15-Day mental health badge", + "item": [ + { + "name": "Create badge", + "item": [ + { + "name": "Create badge", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"BADGE_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Participant is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + "\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"CategoryId\": \"{{BADGE_CATEGORY_ID}}\",\r\n \"Name\": \"Mental health 15-Day Badge\",\r\n \"Description\": \"Badge awarded choosing mental health monitoring for 15-days consistently.\",\r\n \"ImageUrl\": \"https://e7.pngegg.com/pngimages/626/893/png-clipart-blue-and-white-check-logo-facebook-social-media-verified-badge-logo-vanity-url-blue-checkmark-blue-angle.png\"\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/badges", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badges" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get badge by id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/badges/{{BADGE_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badges", + "{{BADGE_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + }, + { + "name": "Create schema", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"SCHEMA_ID\", jsonRes.Data.id);\r", + " pm.environment.set(\"SCHEMA_ROOT_NODE_ID\", jsonRes.Data.RootNode.id);\r", + " pm.environment.set(\"NODE_01_ID\", jsonRes.Data.RootNode.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Client');\r", + " pm.expect(jsonRes.Data.Client).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", + " pm.expect(jsonRes.Data).to.have.property('RootNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Mental health 15-Day Badgee\",\r\n \"Description\": \"This schema represents a badge award logic when a patient takes chooses mental health monitoring for 15 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{MENTAL_HEALTH_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract mental health data\",\r\n \"Description\": \"Extract mental health data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract mental health data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"MentalHealth\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"Any\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting mental health data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:MentalHealth\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/schema", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "schema" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "01 - Get root Node - Extract mental health data", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_01_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is retrieved\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_01_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_01_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "02 - Create next node - Calculate Continuity", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_02_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_01_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Calculate continuity\",\r\n \"Description\": \"This execution step involves calculating the continuity for mental health monitoring consecutively for 15-days.\",\r\n \"Action\": {\r\n \"ActionType\": \"Process-Data\",\r\n \"Name\": \"Calculate Continuity\",\r\n \"InputParams\": {\r\n \"RecordType\": \"MentalHealth\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Extract-Data:MentalHealth\",\r\n \"DataActionType\": \"Calculate-Continuity\",\r\n \"KeyDataType\": \"Date\",\r\n \"KeyName\": \"Date\",\r\n \"ValueDataType\": \"Float\",\r\n \"ValueName\": \"Duration\",\r\n \"Operator\": \"Exists\",\r\n \"ContinuityCount\": 15\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Processing records for 15-day mental health monitoring continuity\",\r\n \"OutputTag\": \"Calculate-Continuity:MentalHealth\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 01", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_02_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_01_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_01_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "03 - Create next node - Extract existing badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_03_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_02_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Get existing badges\",\r\n \"Description\": \"Extract existing 15-day mental health monitoring badges for the participant.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract-Badges\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Database\",\r\n \"InputTag\": \"Badge\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"MentalHealth\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"Mental health 15-Day Badge\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting 15-day mental health badges\",\r\n \"OutputTag\": \"Extract-Data:Badge\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 02", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_03_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_02_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_02_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "04 - Create next node - Compare badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_04_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_03_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Compare badges\",\r\n \"Description\": \"Compare calculated badges against existing badges for 15-day mental health monitoring.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Compare-Data\",\r\n \"Name\": \"Compare badges\",\r\n \"Description\": \"Compare calculated badges against existing badges for 15-day mental health monitoring\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Calculate-Continuity:MentalHealth\",\r\n \"SecondaryInputTag\": \"Extract-Data:Badge\",\r\n \"DataActionType\": \"Find-Range-Difference\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"MentalHealth\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"Mental health 15-Day Badge\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Comparing badges and get updated badge list for 15-Day mental health monitoring.\",\r\n \"OutputTag\": \"Compare-Data:Badge\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 03", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_04_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_03_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_03_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "05 - Create next node - Store updated badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_05_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_04_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Store updated badges\",\r\n \"Description\": \"Store updated 15-day mental health monitoring badges for the participant.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Store-Data\",\r\n \"Name\": \"Store updated badges\",\r\n \"Description\": \"Store updated 15-day mental health monitoring badges for the participant.\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Compare-Data:Badge\",\r\n \"StorageKeys\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"MentalHealth\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"Mental health 15-Day Badge\"\r\n },\r\n {\r\n \"Key\": \"BadgeId\",\r\n \"Value\": \"{{BADGE_ID}}\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting 15-day mental health monitoring badges\",\r\n \"OutputTag\": \"Store-Data:Badge\",\r\n \"DestinationType\": \"Database\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 04", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_05_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_04_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_04_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get schema by Id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Client');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", + " pm.expect(jsonRes.Data).to.have.property('RootNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/engine/schema/{{SCHEMA_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "schema", + "{{SCHEMA_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + }, + { + "name": "Schema-30-Day mental health badge", + "item": [ + { + "name": "Create badge", + "item": [ + { + "name": "Create badge", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"BADGE_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Participant is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + "\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"CategoryId\": \"{{BADGE_CATEGORY_ID}}\",\r\n \"Name\": \"Mental health 30-Day Badge\",\r\n \"Description\": \"Badge awarded choosing mental health monitoring for 30-days consistently.\",\r\n \"ImageUrl\": \"https://e7.pngegg.com/pngimages/626/893/png-clipart-blue-and-white-check-logo-facebook-social-media-verified-badge-logo-vanity-url-blue-checkmark-blue-angle.png\"\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/badges", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badges" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get badge by id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/badges/{{BADGE_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badges", + "{{BADGE_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + }, + { + "name": "Create schema", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"SCHEMA_ID\", jsonRes.Data.id);\r", + " pm.environment.set(\"SCHEMA_ROOT_NODE_ID\", jsonRes.Data.RootNode.id);\r", + " pm.environment.set(\"NODE_01_ID\", jsonRes.Data.RootNode.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Client');\r", + " pm.expect(jsonRes.Data.Client).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", + " pm.expect(jsonRes.Data).to.have.property('RootNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Mental health 30-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient takes chooses mental health monitoring for 30 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{MENTAL_HEALTH_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract mental health data\",\r\n \"Description\": \"Extract mental health data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract mental health data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"MentalHealth\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"Any\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting mental health data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:MentalHealth\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/schema", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "schema" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "01 - Get root Node - Extract mental health data", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_01_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is retrieved\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_01_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_01_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "02 - Create next node - Calculate Continuity", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_02_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_01_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Calculate continuity\",\r\n \"Description\": \"This execution step involves calculating the continuity for mental health monitoring consecutively for 30-days.\",\r\n \"Action\": {\r\n \"ActionType\": \"Process-Data\",\r\n \"Name\": \"Calculate Continuity\",\r\n \"InputParams\": {\r\n \"RecordType\": \"MentalHealth\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Extract-Data:MentalHealth\",\r\n \"DataActionType\": \"Calculate-Continuity\",\r\n \"KeyDataType\": \"Date\",\r\n \"KeyName\": \"Date\",\r\n \"ValueDataType\": \"Float\",\r\n \"ValueName\": \"Duration\",\r\n \"Operator\": \"Exists\",\r\n \"ContinuityCount\": 30\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Processing records for 30-day mental health monitoring continuity\",\r\n \"OutputTag\": \"Calculate-Continuity:MentalHealth\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 01", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_02_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_01_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_01_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "03 - Create next node - Extract existing badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_03_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_02_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Get existing badges\",\r\n \"Description\": \"Extract existing 30-day mental health monitoring badges for the participant.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract-Badges\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Database\",\r\n \"InputTag\": \"Badge\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"MentalHealth\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"Mental health 30-Day Badge\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting 30-day mental health monitoring badges\",\r\n \"OutputTag\": \"Extract-Data:Badge\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 02", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_03_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_02_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_02_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "04 - Create next node - Compare badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_04_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_03_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Compare badges\",\r\n \"Description\": \"Compare calculated badges against existing badges for 30-day mental health monitoring.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Compare-Data\",\r\n \"Name\": \"Compare badges\",\r\n \"Description\": \"Compare calculated badges against existing badges for 30-day mental health monitoring.\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Calculate-Continuity:MentalHealth\",\r\n \"SecondaryInputTag\": \"Extract-Data:Badge\",\r\n \"DataActionType\": \"Find-Range-Difference\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"MentalHealth\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"Mental health 30-Day Badge\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Comparing badges and get updated badge list for 30-Day mental health monitoring badges.\",\r\n \"OutputTag\": \"Compare-Data:Badge\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 03", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_04_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_03_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_03_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "05 - Create next node - Store updated badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_05_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_04_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Store updated badges\",\r\n \"Description\": \"Store updated 30-day mental health monitoring badges for the participant.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Store-Data\",\r\n \"Name\": \"Store updated badges\",\r\n \"Description\": \"Store updated 30-day mental health monitoring badges for the participant.\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Compare-Data:Badge\",\r\n \"StorageKeys\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"MentalHealth\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"Mental health 30-Day Badge\"\r\n },\r\n {\r\n \"Key\": \"BadgeId\",\r\n \"Value\": \"{{BADGE_ID}}\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting 30-day mental health badges monitoring\",\r\n \"OutputTag\": \"Store-Data:Badge\",\r\n \"DestinationType\": \"Database\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 04", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_05_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_04_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_04_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get schema by Id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Client');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", + " pm.expect(jsonRes.Data).to.have.property('RootNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/engine/schema/{{SCHEMA_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "schema", + "{{SCHEMA_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + } + ] + } + ] + } + ] + }, + { + "name": "Get context for participant / reference id", + "item": [ + { + "name": "Get schema instance by id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"SCHEMA_INSTANCE_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema instance is returned\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Client');\r", + " pm.expect(jsonRes.Data.Client).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", + " pm.expect(jsonRes.Data).to.have.property('RootNodeId');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Medication 7 Day Badge Rule\",\r\n \"Description\": \"This rule represents logical steps involved in awarding a badge for consecutive 7 days.\",\r\n \"ParentNodeId\": \"{{SCHEMA_ROOT_NODE_ID}}\",\r\n \"Action\": {\r\n \"ActionType\": \"{{AWARD_BADGE_EVENT_TYPE}}\",\r\n \"Name\": \"Medication 7-Days Badge\",\r\n \"Description\": \"This rule represents logical steps involved in awarding a badge for consecutive 7 days.\",\r\n \"Params\": {\r\n \"Message\": \"Award medication 7-days badge.\",\r\n \"Action\": \"{{AWARD_BADGE_EVENT_TYPE}}\",\r\n \"NextNodeId\": null,\r\n \"Extra\": {}\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/schema-instances/{{SCHEMA_INSTANCE_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "schema-instances", + "{{SCHEMA_INSTANCE_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + }, + { + "name": "Get participant badges", + "item": [ + { + "name": "Get participant by reference id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"PARTICIPANT_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema instance is returned\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Client');\r", + " pm.expect(jsonRes.Data.Client).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", + " pm.expect(jsonRes.Data).to.have.property('RootNodeId');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/participants/by-reference-id/{{REFERENCE_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "participants", + "by-reference-id", + "{{REFERENCE_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get participant badges", + "event": [ + { + "listen": "test", + "script": { "exec": [ "try {\r", " var jsonRes = pm.response.json();\r", @@ -12621,6 +15919,92 @@ "response": [] } ] + }, + { + "name": "Badges", + "item": [ + { + "name": "Get badge stock images", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"PARTICIPANT_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema instance is returned\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Client');\r", + " pm.expect(jsonRes.Data.Client).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", + " pm.expect(jsonRes.Data).to.have.property('RootNodeId');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/badges/stock-images", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badges", + "stock-images" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] } ] } \ No newline at end of file diff --git a/src/modules/fact.extractors/facts.db.connector.ts b/src/modules/fact.extractors/facts.db.connector.ts index c9338c7..cc4e9f7 100644 --- a/src/modules/fact.extractors/facts.db.connector.ts +++ b/src/modules/fact.extractors/facts.db.connector.ts @@ -8,6 +8,7 @@ import { MedicationFact } from './models/medication.fact.model'; import { DBLogger } from "./../../database/database.logger"; import { NutritionChoiceFact } from "./models/nutrition.choice.fact.model"; import { ExercisePhysicalActivityFact } from "./models/exercise.physical.activity.fact.model"; +import { MentalHealthFact } from "./models/mental.health.fact.model"; /////////////////////////////////////////////////////////////////////////////////// const DATABASE_NAME = `awards_facts`; @@ -30,6 +31,7 @@ class FactsDatabaseConnector { BadgeFact, NutritionChoiceFact, ExercisePhysicalActivityFact, + MentalHealthFact, ], migrations : [], subscribers : [], diff --git a/src/modules/fact.extractors/models/mental.health.fact.model.ts b/src/modules/fact.extractors/models/mental.health.fact.model.ts new file mode 100644 index 0000000..d1c1630 --- /dev/null +++ b/src/modules/fact.extractors/models/mental.health.fact.model.ts @@ -0,0 +1,37 @@ +import "reflect-metadata"; +import { + Column, + Entity, + PrimaryGeneratedColumn, +} from 'typeorm'; + +//////////////////////////////////////////////////////////////////////// + +@Entity({ name: 'mental_health_facts' }) +export class MentalHealthFact { + + @PrimaryGeneratedColumn('uuid') + id : string; + + @Column({ type: 'uuid', nullable: false }) + ContextReferenceId : string; + + @Column({ type: 'uuid', nullable: true }) + RecordId : string; + + @Column({ type: 'varchar', length: 256, nullable: true }) + Name : string; + + @Column({ nullable: true }) + Duration: number; + + @Column({ type: 'varchar', length: 128, nullable: true }) + Unit : string; + + @Column({ nullable: true }) + RecordDate : Date; + + @Column({ nullable: true }) + RecordDateStr : string; + +} diff --git a/src/modules/processor/providers/implementation/data.extractors/data.extractor.ts b/src/modules/processor/providers/implementation/data.extractors/data.extractor.ts index b18b0e7..09b1a18 100644 --- a/src/modules/processor/providers/implementation/data.extractors/data.extractor.ts +++ b/src/modules/processor/providers/implementation/data.extractors/data.extractor.ts @@ -10,6 +10,7 @@ import { MedicationDataExtractor } from './medication.data.extractor'; import { BadgeDataExtractor } from "./badge.data.extractor"; import { NutritionDataExtractor } from "./nutrition.data.extractor"; import { ExercisePhysicalActivityDataExtractor } from "./exercise.physical.activity.data.extractor"; +import { MentalHealthDataExtractor } from "./mental.health.data.extractor"; ////////////////////////////////////////////////////////////////////// @@ -65,6 +66,9 @@ export class DataExtractor implements IDataExtractor { else if (recordType === 'Exercise') { return new ExercisePhysicalActivityDataExtractor(); } + else if (recordType === 'MentalHealth') { + return new MentalHealthDataExtractor(); + } return null; }; diff --git a/src/modules/processor/providers/implementation/data.extractors/mental.health.data.extractor.ts b/src/modules/processor/providers/implementation/data.extractors/mental.health.data.extractor.ts new file mode 100644 index 0000000..b9ca920 --- /dev/null +++ b/src/modules/processor/providers/implementation/data.extractors/mental.health.data.extractor.ts @@ -0,0 +1,83 @@ +import { Repository } from "typeorm"; +import { FactsSource } from '../../../../fact.extractors/facts.db.connector'; +import { Context } from "../../../../../database/models/engine/context.model"; +import { DataExtractionInputParams, DataSamplingMethod, OutputParams, ProcessorResult } from '../../../../../domain.types/engine/engine.types'; +import { IExtractor } from "./extractor.interface"; +import { MentalHealthFact } from "../../../../../modules/fact.extractors/models/mental.health.fact.model"; + +////////////////////////////////////////////////////////////////////// + +export class MentalHealthDataExtractor implements IExtractor { + + //#region Repositories + + _mentalHealthRepository: Repository = FactsSource.getRepository(MentalHealthFact); + + //#endregion + + public extract = async ( + context: Context, + inputParams: DataExtractionInputParams, + outputParams: OutputParams) => { + + const filters = inputParams.Filters ?? {}; + var samplingMethod = filters['SamplingMethod'] as DataSamplingMethod; + if (!samplingMethod) { + samplingMethod = DataSamplingMethod.Any; + } + + const records = await this._mentalHealthRepository.find({ + where : { + ContextReferenceId : context.ReferenceId + }, + }); + + const groupedRecords = records.reduce((acc, obj) => { + const key = obj.RecordDateStr; + if (!acc[key]) { + acc[key] = []; + } + acc[key].push(obj); + return acc; + }, {}); + + const dayStats: { Day: string; Passed: boolean;}[] = []; + if (samplingMethod === DataSamplingMethod.Any) { + for (var grKey of Object.keys(groupedRecords)) { + const arr = groupedRecords[grKey]; + const passed = arr.some(obj => obj.Duration != null); // Check only for one record per day + dayStats.push({ + Day : grKey, + Passed : passed, + }); + } + } + else { + for (var grKey of Object.keys(groupedRecords)) { + const arr = groupedRecords[grKey]; + const passed = arr.every(obj => obj.Duration != null); // Check all records for the day + dayStats.push({ + Day : grKey, + Passed : passed, + }); + } + } + + const sorted = dayStats.sort((a, b) => Date.parse(a.Day) - Date.parse(b.Day)); + const transformed = sorted.map(x => { + return { + key : new Date(x.Day), + value : x.Passed, + }; + }); + + const result: ProcessorResult = { + Success : true, + Tag : outputParams.OutputTag, + Data : transformed + }; + + return result; + }; + +} From c6dd3c76627b3fe7a0eb7cba2debe0f61d1d5ed3 Mon Sep 17 00:00:00 2001 From: tabbasum-rean Date: Mon, 5 Jun 2023 18:57:52 +0530 Subject: [PATCH 25/66] Added Vitals images of correct size --- .../stock.badge.images/15-Day Vitals.png | Bin 1736 -> 4918 bytes .../stock.badge.images/30-Day Vitals.png | Bin 1971 -> 5499 bytes .../stock.badge.images/7-Day Vitals.png | Bin 2026 -> 6056 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/images/stock.badge.images/15-Day Vitals.png b/assets/images/stock.badge.images/15-Day Vitals.png index ea3eaa68694c1363aa75317a63397efc08c18ce8..e06b77bae1f4405072bdcfefc2c325813cdc671b 100644 GIT binary patch literal 4918 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 FV1h6|=n4P; diff --git a/assets/images/stock.badge.images/7-Day Vitals.png b/assets/images/stock.badge.images/7-Day Vitals.png index a5307534095830f3cd37d7bbe3a8904251e60872..48e536efb4f9ba4f71eaf6234262e01550e3c29b 100644 GIT binary patch literal 6056 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 i?Py0k+R=_Scl#em1 zW#zh`@5Za%vX|nwoA1V}^5NF)*vjwHyWX*u=)0WLq>1mwtG9n*#*k~gg=yTgnZuEG z;J&8p&9>#nvF6IS@ZHeXt(451f$Y@7>CeB_sgBa3g2|O|&6;=JxS*$YSMJxx&!dar zu#oxj>*lzanPW)>c!uQw001>~QchC<@zOXy7_a{DP+au+4E5QbwXHjd+* zb1cRXNeD2AJJ^~0|6jK1mNwyP$_mUw91Zb>c8&CL-unm&#P11{}hFnpYj zZmwk0@#KjR=CmdTUX&W2@te0vf2c0AGK4`;_F!}H;z;l#CsX77+A%N-2Q zRQ+)hS(fD@_)BboQ^$kGr^nGbEiRXL(DqP5`C{5ET#Ed{{nZDT^=zo zA0L#?`cBi+vTR#W|1Q~Z$Kgz~Cj^M-I!T#}f0zKPbr<<_&|aIt+KOz08{~ z(h-#8z$`jZLU%k33EyMg9wujS*P!3+v5RsnyYK#?O|CR@s;a+rdn7pKyC6Y}m%TZO158(qVG}H-9&8KSBm^-W58R{(V}u zwz(POGpq{OVUcyvE8drWW0(rqtm8BV-K&~x8_lI5D+@3$BP^ExSV z3OXv_udh*QwuuJeL`M-;_6X8NgUDIdMd$gS4fF!Wq&OWN!t@}pB+yy0rZk0*<^k~B zk{&5YCycVMX=3V`p<-ouUdWGvYF*YY#_`B74&^l9WAcR^w7JHVpqWG0()U`I0{SIw ziu5O6J7g-H)il~G!01}irSEH6sPEOL*Zo6A4RnEWfZLfWzd~HKavQmsjo+x6YCBp- zu=JMW1JhGjqcfe~wY;>TN{v4Sj#D$rj+~xu2WnE)okKUTCvDBnX`wEPT+O^iT9f1c zN%aOQC!dsc_azPL!IL5p0tpjHMpg31?P&CHDIfVZyd5kS8Ub6klR^d1uoii0)=npF>K!N+ zZpKhsr>wcdrE$yFi$N~J9j9Z=k8*sdn)Ewv7osT}Ax$K?Xhafu+&T?G?B8_^U39xy zn3m1k%V{pN-yRwYR^si!F-joMxU?_7iNm3?Vs^ofGfhKv-uyw`+MJ_wUfdT9# z%3&SegQ;y2=Tb<+Fi^>i78|wv(xDmX96(&>OOD&5)!`lQX!wHLM#-+`It7A^=24J9 zU79Q-Ig_X`%k?Lbd54=jZ*s)J$SoF?uqD+&0@s&OLA4c8fB}|*ByqCjxCHo5M;(jQ z8)=n-35;#L2;{cc3*dptyX~tNS~8C0V-GIg2AVxXr){GdL6!bQkuf(=4eR)$g|Rvt zN{Ns@2EMP!l@VyRZNM8PLgmH@WXV>?79L|!TY5n<>R}22j%N(>`IO@jb=VT1KPh9Y zX0np9HxEi?oUHtl4{=m1U(~UdgbPp6W0?}_!do#S)Wf}}x0@5~c9N+hG2i8c@zpGl zqh1ccU>0#kc%&MwbaKWK%vs!>g)Og%eiQPGg0nxJ;8W}9nMED7Hh#7Pu)fuuS_}NVy&Am zK}&mII2mW^JcM!K$R8TJ6uo2r1+?+^y?(y``IpfD$TjNqub_Y6&#%VSwKnR>;?B6T z*Uv5D?)j?df4Zf>==q9*{M@QleqIgzy3_dkO6YyF{f}#)XZtIz*UQnrzN_W#E=B+N zzQdh+5&E^asC_;kJv*>m1N$8G&GWCrCG+p+tNj=9|8|M}3qq{dfR3)v(f|Me07*qo IM6N<$g3*&4T>t<8 From 72100c87d61e9217866a63891fe7d4caf65d31eb Mon Sep 17 00:00:00 2001 From: tabbasum-rean Date: Mon, 5 Jun 2023 22:09:56 +0530 Subject: [PATCH 26/66] Change badge name --- ...ll-being..png => Mental health 15-Day Badge.png} | Bin ...ll-being..png => Mental health 30-Day Badge.png} | Bin ...Well-being.png => Mental health 7-Day Badge.png} | Bin 3 files changed, 0 insertions(+), 0 deletions(-) rename assets/images/stock.badge.images/{15-Day Mental Well-being..png => Mental health 15-Day Badge.png} (100%) rename assets/images/stock.badge.images/{30-Day Mental Well-being..png => Mental health 30-Day Badge.png} (100%) rename assets/images/stock.badge.images/{7-Day Mental Well-being.png => Mental health 7-Day Badge.png} (100%) diff --git a/assets/images/stock.badge.images/15-Day Mental Well-being..png b/assets/images/stock.badge.images/Mental health 15-Day Badge.png similarity index 100% rename from assets/images/stock.badge.images/15-Day Mental Well-being..png rename to assets/images/stock.badge.images/Mental health 15-Day Badge.png diff --git a/assets/images/stock.badge.images/30-Day Mental Well-being..png b/assets/images/stock.badge.images/Mental health 30-Day Badge.png similarity index 100% rename from assets/images/stock.badge.images/30-Day Mental Well-being..png rename to assets/images/stock.badge.images/Mental health 30-Day Badge.png diff --git a/assets/images/stock.badge.images/7-Day Mental Well-being.png b/assets/images/stock.badge.images/Mental health 7-Day Badge.png similarity index 100% rename from assets/images/stock.badge.images/7-Day Mental Well-being.png rename to assets/images/stock.badge.images/Mental health 7-Day Badge.png From 1fa37484b43ba5ec5e82816d1de342d4fa055070 Mon Sep 17 00:00:00 2001 From: vinay-debug <84920398+vinay-debug@users.noreply.github.com> Date: Tue, 6 Jun 2023 14:29:15 +0530 Subject: [PATCH 27/66] postman for vitals award --- .../awards service.postman_collection.json | 3222 ++++++++++++++++- 1 file changed, 3221 insertions(+), 1 deletion(-) diff --git a/postman/awards service.postman_collection.json b/postman/awards service.postman_collection.json index c3aac99..f43f033 100644 --- a/postman/awards service.postman_collection.json +++ b/postman/awards service.postman_collection.json @@ -1,6 +1,6 @@ { "info": { - "_postman_id": "d38423ff-1dbb-43c9-99a2-3c23bc63590e", + "_postman_id": "29ce7b9b-655c-45f2-833c-2430e2143603", "name": "Awards service", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", "_exporter_id": "15905052" @@ -11935,6 +11935,3226 @@ ] } ] + }, + { + "name": "vital badges", + "item": [ + { + "name": "Create badge category", + "item": [ + { + "name": "Create badge category", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"BADGE_CATEGORY_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Participant is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Vital\",\r\n \"Description\": \"Badge category for vital related badges\",\r\n \"ImageUrl\": \"https://e7.pngegg.com/pngimages/626/893/png-clipart-blue-and-white-check-logo-facebook-social-media-verified-badge-logo-vanity-url-blue-checkmark-blue-angle.png\"\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/badge-categories", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badge-categories" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get badge category by id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/badge-categories/{{BADGE_CATEGORY_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badge-categories", + "{{BADGE_CATEGORY_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + }, + { + "name": "Schema-7-Day vital badge", + "item": [ + { + "name": "Create badge", + "item": [ + { + "name": "Create badge", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"BADGE_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Participant is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + "\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"CategoryId\": \"{{BADGE_CATEGORY_ID}}\",\r\n \"Name\": \"7-Day Vitals\",\r\n \"Description\": \"Badge awarded for monitoring body vitals for 7-days consistently.\",\r\n \"ImageUrl\": \"https://e7.pngegg.com/pngimages/626/893/png-clipart-blue-and-white-check-logo-facebook-social-media-verified-badge-logo-vanity-url-blue-checkmark-blue-angle.png\"\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/badges", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badges" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get badge by id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/badges/{{BADGE_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badges", + "{{BADGE_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + }, + { + "name": "Create schema", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"SCHEMA_ID\", jsonRes.Data.id);\r", + " pm.environment.set(\"SCHEMA_ROOT_NODE_ID\", jsonRes.Data.RootNode.id);\r", + " pm.environment.set(\"NODE_01_ID\", jsonRes.Data.RootNode.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Client');\r", + " pm.expect(jsonRes.Data.Client).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", + " pm.expect(jsonRes.Data).to.have.property('RootNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Vital Monitoring 7-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient monitor body vitals for 7 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{VITAL_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract vital data\",\r\n \"Description\": \"Extract vital data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract vital data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Vital\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"Any\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting vital data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:Vital\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/schema", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "schema" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "01 - Get root Node - Extract nutrition data", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_01_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is retrieved\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_01_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_01_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "02 - Create next node - Calculate Continuity", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_02_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_01_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Calculate continuity\",\r\n \"Description\": \"This execution step involves calculating the continuity for monitoring body vital consecutively for 7-days.\",\r\n \"Action\": {\r\n \"ActionType\": \"Process-Data\",\r\n \"Name\": \"Calculate Continuity\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Vital\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Extract-Data:Vital\",\r\n \"DataActionType\": \"Calculate-Continuity\",\r\n \"KeyDataType\": \"Date\",\r\n \"KeyName\": \"Date\",\r\n \"ValueDataType\": \"Float\",\r\n \"ValueName\": \"VitalPrimaryValue\",\r\n \"Operator\": \"Exists\",\r\n \"ContinuityCount\": 7\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Processing records for 7-day body vitals continuity\",\r\n \"OutputTag\": \"Calculate-Continuity:Vital\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 01", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_02_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_01_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_01_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "03 - Create next node - Extract existing badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_03_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_02_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Get existing badges\",\r\n \"Description\": \"Extract existing 7-day vital monitoring badges for the participant.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract-Badges\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Database\",\r\n \"InputTag\": \"Badge\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"Vital\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"7-Day Vitals\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting 7-day vital monitoring badges\",\r\n \"OutputTag\": \"Extract-Data:Badge\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 02", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_03_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_02_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_02_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "04 - Create next node - Compare badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_04_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_03_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Compare badges\",\r\n \"Description\": \"Compare calculated badges against existing badges for 7-day vital monitoring.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Compare-Data\",\r\n \"Name\": \"Compare badges\",\r\n \"Description\": \"Compare calculated badges against existing badges for 7-day vital monitoring\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Calculate-Continuity:Vital\",\r\n \"SecondaryInputTag\": \"Extract-Data:Badge\",\r\n \"DataActionType\": \"Find-Range-Difference\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"Vital\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"7-Day Vitals\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Comparing badges and get updated badge list for 7-day vital monitoring badges.\",\r\n \"OutputTag\": \"Compare-Data:Badge\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 03", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_04_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_03_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_03_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "05 - Create next node - Store updated badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_05_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_04_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Store updated badges\",\r\n \"Description\": \"Store updated 7-day vital monitoring badges for the participant.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Store-Data\",\r\n \"Name\": \"Store updated badges\",\r\n \"Description\": \"Store updated 7-day vital monitoring badges for the participant.\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Compare-Data:Badge\",\r\n \"StorageKeys\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"Vital\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"7-Day Vitals\"\r\n },\r\n {\r\n \"Key\": \"BadgeId\",\r\n \"Value\": \"{{BADGE_ID}}\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting 7-day vital monitoring badges\",\r\n \"OutputTag\": \"Store-Data:Badge\",\r\n \"DestinationType\": \"Database\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 04", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_05_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_04_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_04_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get schema by Id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Client');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", + " pm.expect(jsonRes.Data).to.have.property('RootNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/engine/schema/{{SCHEMA_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "schema", + "{{SCHEMA_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + }, + { + "name": "Schema-15-Day vital badge", + "item": [ + { + "name": "Create badge", + "item": [ + { + "name": "Create badge", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"BADGE_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Participant is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + "\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"CategoryId\": \"{{BADGE_CATEGORY_ID}}\",\r\n \"Name\": \"15-Day Vitals\",\r\n \"Description\": \"Badge awarded for monitoring body vitals for 15-days consistently.\",\r\n \"ImageUrl\": \"https://e7.pngegg.com/pngimages/626/893/png-clipart-blue-and-white-check-logo-facebook-social-media-verified-badge-logo-vanity-url-blue-checkmark-blue-angle.png\"\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/badges", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badges" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get badge by id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/badges/{{BADGE_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badges", + "{{BADGE_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + }, + { + "name": "Create schema", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"SCHEMA_ID\", jsonRes.Data.id);\r", + " pm.environment.set(\"SCHEMA_ROOT_NODE_ID\", jsonRes.Data.RootNode.id);\r", + " pm.environment.set(\"NODE_01_ID\", jsonRes.Data.RootNode.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Client');\r", + " pm.expect(jsonRes.Data.Client).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", + " pm.expect(jsonRes.Data).to.have.property('RootNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Vital Monitoring 15-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient monitor body vitals for 15 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{VITAL_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract vital data\",\r\n \"Description\": \"Extract vital data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract vital data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Vital\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"Any\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting vital data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:Vital\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/schema", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "schema" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "01 - Get root Node - Extract nutrition data", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_01_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is retrieved\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_01_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_01_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "02 - Create next node - Calculate Continuity", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_02_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_01_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Calculate continuity\",\r\n \"Description\": \"This execution step involves calculating the continuity for monitoring body vital consecutively for 15-days.\",\r\n \"Action\": {\r\n \"ActionType\": \"Process-Data\",\r\n \"Name\": \"Calculate Continuity\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Vital\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Extract-Data:Vital\",\r\n \"DataActionType\": \"Calculate-Continuity\",\r\n \"KeyDataType\": \"Date\",\r\n \"KeyName\": \"Date\",\r\n \"ValueDataType\": \"Float\",\r\n \"ValueName\": \"VitalPrimaryValue\",\r\n \"Operator\": \"Exists\",\r\n \"ContinuityCount\": 15\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Processing records for 15-day body vitals continuity\",\r\n \"OutputTag\": \"Calculate-Continuity:Vital\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 01", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_02_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_01_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_01_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "03 - Create next node - Extract existing badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_03_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_02_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Get existing badges\",\r\n \"Description\": \"Extract existing 15-day vital monitoring badges for the participant.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract-Badges\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Database\",\r\n \"InputTag\": \"Badge\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"Vital\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"15-Day Vitals\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting 15-day vital monitoring badges\",\r\n \"OutputTag\": \"Extract-Data:Badge\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 02", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_03_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_02_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_02_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "04 - Create next node - Compare badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_04_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_03_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Compare badges\",\r\n \"Description\": \"Compare calculated badges against existing badges for 15-day vital monitoring.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Compare-Data\",\r\n \"Name\": \"Compare badges\",\r\n \"Description\": \"Compare calculated badges against existing badges for 15-day vital monitoring\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Calculate-Continuity:Vital\",\r\n \"SecondaryInputTag\": \"Extract-Data:Badge\",\r\n \"DataActionType\": \"Find-Range-Difference\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"Vital\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"15-Day Vitals\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Comparing badges and get updated badge list for 15-day vital monitoring badges.\",\r\n \"OutputTag\": \"Compare-Data:Badge\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 03", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_04_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_03_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_03_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "05 - Create next node - Store updated badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_05_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_04_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Store updated badges\",\r\n \"Description\": \"Store updated 15-day vital monitoring badges for the participant.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Store-Data\",\r\n \"Name\": \"Store updated badges\",\r\n \"Description\": \"Store updated 15-day vital monitoring badges for the participant.\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Compare-Data:Badge\",\r\n \"StorageKeys\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"Vital\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"15-Day Vitals\"\r\n },\r\n {\r\n \"Key\": \"BadgeId\",\r\n \"Value\": \"{{BADGE_ID}}\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting 15-day vital monitoring badges\",\r\n \"OutputTag\": \"Store-Data:Badge\",\r\n \"DestinationType\": \"Database\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 04", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_05_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_04_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_04_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get schema by Id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Client');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", + " pm.expect(jsonRes.Data).to.have.property('RootNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/engine/schema/{{SCHEMA_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "schema", + "{{SCHEMA_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + }, + { + "name": "Schema-30-Day vital badge", + "item": [ + { + "name": "Create badge", + "item": [ + { + "name": "Create badge", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"BADGE_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Participant is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + "\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"CategoryId\": \"{{BADGE_CATEGORY_ID}}\",\r\n \"Name\": \"30-Day Vitals\",\r\n \"Description\": \"Badge awarded for monitoring body vitals for 30-days consistently.\",\r\n \"ImageUrl\": \"https://e7.pngegg.com/pngimages/626/893/png-clipart-blue-and-white-check-logo-facebook-social-media-verified-badge-logo-vanity-url-blue-checkmark-blue-angle.png\"\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/badges", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badges" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get badge by id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/badges/{{BADGE_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "badges", + "{{BADGE_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + }, + { + "name": "Create schema", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"SCHEMA_ID\", jsonRes.Data.id);\r", + " pm.environment.set(\"SCHEMA_ROOT_NODE_ID\", jsonRes.Data.RootNode.id);\r", + " pm.environment.set(\"NODE_01_ID\", jsonRes.Data.RootNode.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Client');\r", + " pm.expect(jsonRes.Data.Client).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", + " pm.expect(jsonRes.Data).to.have.property('RootNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Vital Monitoring 30-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient monitor body vitals for 30 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{VITAL_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract vital data\",\r\n \"Description\": \"Extract vital data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract vital data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Vital\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"Any\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting vital data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:Vital\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/schema", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "schema" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "01 - Get root Node - Extract nutrition data", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_01_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is retrieved\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_01_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_01_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "02 - Create next node - Calculate Continuity", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_02_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_01_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Calculate continuity\",\r\n \"Description\": \"This execution step involves calculating the continuity for monitoring body vital consecutively for 30-days.\",\r\n \"Action\": {\r\n \"ActionType\": \"Process-Data\",\r\n \"Name\": \"Calculate Continuity\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Vital\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Extract-Data:Vital\",\r\n \"DataActionType\": \"Calculate-Continuity\",\r\n \"KeyDataType\": \"Date\",\r\n \"KeyName\": \"Date\",\r\n \"ValueDataType\": \"Float\",\r\n \"ValueName\": \"VitalPrimaryValue\",\r\n \"Operator\": \"Exists\",\r\n \"ContinuityCount\": 30\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Processing records for 30-day body vitals continuity\",\r\n \"OutputTag\": \"Calculate-Continuity:Vital\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 01", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_02_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_01_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_01_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "03 - Create next node - Extract existing badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_03_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_02_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Get existing badges\",\r\n \"Description\": \"Extract existing 30-day vital monitoring badges for the participant.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract-Badges\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Database\",\r\n \"InputTag\": \"Badge\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"Vital\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"30-Day Vitals\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting 30-day vital monitoring badges\",\r\n \"OutputTag\": \"Extract-Data:Badge\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 02", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_03_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_02_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_02_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "04 - Create next node - Compare badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_04_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_03_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Compare badges\",\r\n \"Description\": \"Compare calculated badges against existing badges for 30-day vital monitoring.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Compare-Data\",\r\n \"Name\": \"Compare badges\",\r\n \"Description\": \"Compare calculated badges against existing badges for 30-day vital monitoring\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Calculate-Continuity:Vital\",\r\n \"SecondaryInputTag\": \"Extract-Data:Badge\",\r\n \"DataActionType\": \"Find-Range-Difference\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"Vital\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"30-Day Vitals\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Comparing badges and get updated badge list for 30-day vital monitoring badges.\",\r\n \"OutputTag\": \"Compare-Data:Badge\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 03", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_04_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_03_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_03_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "05 - Create next node - Store updated badges", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"NODE_05_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(201);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"ParentNodeId\": \"{{NODE_04_ID}}\",\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Store updated badges\",\r\n \"Description\": \"Store updated 30-day vital monitoring badges for the participant.\",\r\n \"Type\": \"Execution-Node\",\r\n \"Action\": {\r\n \"ActionType\": \"Store-Data\",\r\n \"Name\": \"Store updated badges\",\r\n \"Description\": \"Store updated 30-day vital monitoring badges for the participant.\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Badge\",\r\n \"SourceType\": \"Almanac\",\r\n \"InputTag\": \"Compare-Data:Badge\",\r\n \"StorageKeys\": [\r\n {\r\n \"Key\": \"BadgeCategory\",\r\n \"Value\": \"Vital\"\r\n },\r\n {\r\n \"Key\": \"BadgeTitle\",\r\n \"Value\": \"30-Day Vitals\"\r\n },\r\n {\r\n \"Key\": \"BadgeId\",\r\n \"Value\": \"{{BADGE_ID}}\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting 30-day vital monitoring badges\",\r\n \"OutputTag\": \"Store-Data:Badge\",\r\n \"DestinationType\": \"Database\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Update next node for node 04", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "\r", + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Node is updated\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ParentNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Action\": {\r\n \"OutputParams\": {\r\n \"NextNodeId\": \"{{NODE_05_ID}}\"\r\n }\r\n }\r\n}" + }, + "url": { + "raw": "{{BASE_URL}}/engine/nodes/{{NODE_04_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "nodes", + "{{NODE_04_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + }, + { + "name": "Get schema by Id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Request is successfull\", function () {\r", + " pm.response.to.have.status(200);\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Status).to.eql('success');\r", + "});\r", + "\r", + "pm.test(\"Schema is created\", function () {\r", + " var jsonRes = pm.response.json();\r", + " pm.expect(jsonRes.Data).to.have.property('id');\r", + " pm.expect(jsonRes.Data).to.have.property('Client');\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data).to.have.property('Description');\r", + " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", + " pm.expect(jsonRes.Data).to.have.property('RootNode');\r", + "});\r", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + }, + { + "key": "x-api-key", + "value": "{{API_KEY}}", + "type": "text" + }, + { + "key": "Authorization", + "value": "Bearer {{MODERATOR_USER_JWT}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{BASE_URL}}/engine/schema/{{SCHEMA_ID}}", + "host": [ + "{{BASE_URL}}" + ], + "path": [ + "engine", + "schema", + "{{SCHEMA_ID}}" + ] + }, + "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." + }, + "response": [] + } + ] + } + ] } ] } From ec7eae7b5c30aa87faf2778acd73b4d77a5cd4d0 Mon Sep 17 00:00:00 2001 From: tabbasum-rean Date: Wed, 7 Jun 2023 14:08:14 +0530 Subject: [PATCH 28/66] Fixed issue with PublicUrl of badges --- seed.data/role.privileges.json | 2 ++ .../file.resource/file.resource.routes.ts | 2 +- .../mappers/general/file.resource.mapper.ts | 4 ++-- .../services/general/file.resource.service.ts | 10 ++++---- .../file.resource.domain.model.ts | 2 +- .../providers/aws.s3.file.storage.service.ts | 24 ++++++++++++++++++- 6 files changed, 34 insertions(+), 10 deletions(-) diff --git a/seed.data/role.privileges.json b/seed.data/role.privileges.json index 3e63a1e..7b555ee 100644 --- a/seed.data/role.privileges.json +++ b/seed.data/role.privileges.json @@ -18,6 +18,7 @@ "FileResource.GetById", "FileResource.Search", "FileResource.Download", + "FileResource.DownloadByVersionName", "Client.Create", "Client.Search", @@ -48,6 +49,7 @@ "FileResource.GetById", "FileResource.Search", "FileResource.Download", + "FileResource.DownloadByVersionName", "Participant.Create", "Participant.Search", diff --git a/src/api/general/file.resource/file.resource.routes.ts b/src/api/general/file.resource/file.resource.routes.ts index 008da0c..19a4548 100644 --- a/src/api/general/file.resource/file.resource.routes.ts +++ b/src/api/general/file.resource/file.resource.routes.ts @@ -15,7 +15,7 @@ export const register = (app: express.Application): void => { router.get('/:id', authenticator.authenticateUser, controller.getById); router.delete('/:id', authenticator.authenticateUser, controller.delete); - router.get('/:id/download-by-version-name/:version', controller.downloadByVersionName); + router.get('/:id/download-by-version-name/:version', authenticator.authenticateClient, controller.downloadByVersionName); app.use('/api/v1/file-resources', router); }; diff --git a/src/database/mappers/general/file.resource.mapper.ts b/src/database/mappers/general/file.resource.mapper.ts index 1f2ad73..bd5edce 100644 --- a/src/database/mappers/general/file.resource.mapper.ts +++ b/src/database/mappers/general/file.resource.mapper.ts @@ -23,7 +23,7 @@ export class FileResourceMapper { Public : fileResource.Public, Size : fileResource.Size, Tags : fileResource.Tags, - UploadedBy : fileResource.UploadedBy.id, + UploadedBy : null, CreatedAt : fileResource.CreatedAt, UpdatedAt : fileResource.UpdatedAt, }; @@ -36,7 +36,7 @@ export class FileResourceMapper { return null; } - var url = ConfigurationManager.BaseUrl + '/api/v1/file-resources/' + fileVersion.ResourceId + '/download-by-version-name/' + fileVersion.Version; + var url = ConfigurationManager.BaseUrl + '/file-resources/' + fileVersion.ResourceId + '/download-by-version-name/' + fileVersion.Version; var v: FileResourceMetadata = { VersionId : fileVersion.id, diff --git a/src/database/services/general/file.resource.service.ts b/src/database/services/general/file.resource.service.ts index 0ad172c..a446345 100644 --- a/src/database/services/general/file.resource.service.ts +++ b/src/database/services/general/file.resource.service.ts @@ -74,9 +74,9 @@ export class FileResourceService { where : { id : id }, - relations : { + /*relations : { UploadedBy : true - }, + },*/ select : { id : true, OriginalFilename : true, @@ -88,7 +88,7 @@ export class FileResourceService { Size : true, StorageKey : true, Tags : true, - UploadedBy : { + /*UploadedBy : { id : true, Client : { Name : true @@ -96,7 +96,7 @@ export class FileResourceService { FirstName : true, LastName : true, Prefix : true - }, + },*/ }, }); return FileResourceMapper.toResponseDto(record); @@ -288,7 +288,7 @@ export class FileResourceService { FileName : metadata.FileName, IsMultiResolutionImage : false, MimeType : Helper.getMimeType(sourceLocation), - IsPublicResource : isPublicResource, + Public : isPublicResource, }; var resource = await this._fileResourceRepository.create(domainModel); diff --git a/src/domain.types/general/file.resource/file.resource.domain.model.ts b/src/domain.types/general/file.resource/file.resource.domain.model.ts index c9274c3..d937110 100644 --- a/src/domain.types/general/file.resource/file.resource.domain.model.ts +++ b/src/domain.types/general/file.resource/file.resource.domain.model.ts @@ -4,7 +4,7 @@ export interface FileResourceUploadDomainModel { FileMetadata : FileResourceMetadata; OwnerUserId? : string; UploadedByUserId? : string; - IsPublicResource? : boolean; + Public? : boolean; IsMultiResolutionImage? : boolean; MimeType? : string; DefaultVersionId? : string; diff --git a/src/modules/storage/providers/aws.s3.file.storage.service.ts b/src/modules/storage/providers/aws.s3.file.storage.service.ts index 4988886..fd6c2ba 100644 --- a/src/modules/storage/providers/aws.s3.file.storage.service.ts +++ b/src/modules/storage/providers/aws.s3.file.storage.service.ts @@ -74,7 +74,29 @@ export class AWSS3FileStorageService implements IFileStorageService { Bucket : process.env.STORAGE_BUCKET, Key : storageKey, }; - return s3.getObject(params).createReadStream(); + var file = fs.createWriteStream(localFilePath); + + return new Promise((resolve, reject) => { + s3.getObject(params).createReadStream() + .on('end', () => { + + //var st = fs.existsSync(localFilePath); + + var stats = fs.statSync(localFilePath); + var count = 0; + while (stats.size === 0 && count < 5) { + setTimeout(() => { + stats = fs.statSync(localFilePath); + }, 3000); + count++; + } + return resolve(localFilePath); + }) + .on('error', (error) => { + return reject(error); + }) + .pipe(file); + }); } catch (error) { logger.error(error.message); From 3370c5787eed2f98910cd0f15e3b600f2708a1a3 Mon Sep 17 00:00:00 2001 From: tabbasum-rean Date: Wed, 7 Jun 2023 15:05:37 +0530 Subject: [PATCH 29/66] Fixed file resource API route --- src/api/general/file.resource/file.resource.routes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/general/file.resource/file.resource.routes.ts b/src/api/general/file.resource/file.resource.routes.ts index 19a4548..008da0c 100644 --- a/src/api/general/file.resource/file.resource.routes.ts +++ b/src/api/general/file.resource/file.resource.routes.ts @@ -15,7 +15,7 @@ export const register = (app: express.Application): void => { router.get('/:id', authenticator.authenticateUser, controller.getById); router.delete('/:id', authenticator.authenticateUser, controller.delete); - router.get('/:id/download-by-version-name/:version', authenticator.authenticateClient, controller.downloadByVersionName); + router.get('/:id/download-by-version-name/:version', controller.downloadByVersionName); app.use('/api/v1/file-resources', router); }; From d53db8433895afa9f5d6e9541e4ef80339a68499 Mon Sep 17 00:00:00 2001 From: tabbasum-rean Date: Wed, 7 Jun 2023 19:31:52 +0530 Subject: [PATCH 30/66] Fixed issue with badge image upload --- src/modules/storage/providers/aws.s3.file.storage.service.ts | 3 ++- src/startup/seeder.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/modules/storage/providers/aws.s3.file.storage.service.ts b/src/modules/storage/providers/aws.s3.file.storage.service.ts index fd6c2ba..e27a22a 100644 --- a/src/modules/storage/providers/aws.s3.file.storage.service.ts +++ b/src/modules/storage/providers/aws.s3.file.storage.service.ts @@ -30,11 +30,12 @@ export class AWSS3FileStorageService implements IFileStorageService { upload = async (inputStream: any, storageKey: string): Promise => { try { + const fileContent = fs.readFileSync(inputStream); var s3 = this.getS3Client(); const params = { Bucket : process.env.STORAGE_BUCKET, Key : storageKey, - Body : inputStream //Request stream piped directly + Body : fileContent //Request stream piped directly }; var stored = await s3.upload(params).promise(); logger.info(JSON.stringify(stored, null, 2)); diff --git a/src/startup/seeder.ts b/src/startup/seeder.ts index 50a8e65..678edd4 100644 --- a/src/startup/seeder.ts +++ b/src/startup/seeder.ts @@ -203,6 +203,7 @@ export class Seeder { var cloudStoragePath = 'assets/images/stock.badge.images/'; var sourceFilePath = path.join(process.cwd(), "./assets/images/stock.badge.images/"); + var files = fs.readdirSync(sourceFilePath); var imageFiles = files.filter((f) => { return path.extname(f).toLowerCase() === '.png'; @@ -227,7 +228,7 @@ export class Seeder { var badgeStockImage = await this._badgeStockImageService.create(domainModel); if (!badgeStockImage) { - console.log('Error occurred while seeding medication stock images!'); + console.log('Error occurred while seeding badge stock images!'); } } }; From e6037c49145618352a43f3327ef8854eaa3bdcf6 Mon Sep 17 00:00:00 2001 From: Kiran Kharade Date: Sun, 11 Jun 2023 21:28:34 +0530 Subject: [PATCH 31/66] Fixing file resource and badge image upload related issues. --- seed.data/role.privileges.json | 4 ++-- src/api/client/client.controller.ts | 16 ++++++++++++- src/api/client/client.routes.ts | 2 ++ .../file.resource/file.resource.controller.ts | 9 ++++--- .../file.resource/file.resource.routes.ts | 2 +- .../awards/participant.group.mapper.ts | 1 + .../models/awards/participant.group.model.ts | 3 +++ .../awards/participant.group.service.ts | 4 +++- .../services/general/file.resource.service.ts | 24 ++++++++++++------- .../awards/participant.group.domain.types.ts | 6 ++++- .../file.storage.service.interface.ts | 4 ++-- .../providers/aws.s3.file.storage.service.ts | 6 +++-- .../providers/custom.file.storage.service.ts | 7 +++--- src/modules/storage/storage.service.ts | 6 ++--- src/startup/seeder.ts | 14 +++++++---- 15 files changed, 74 insertions(+), 34 deletions(-) diff --git a/seed.data/role.privileges.json b/seed.data/role.privileges.json index 7b555ee..1f29ba8 100644 --- a/seed.data/role.privileges.json +++ b/seed.data/role.privileges.json @@ -18,7 +18,7 @@ "FileResource.GetById", "FileResource.Search", "FileResource.Download", - "FileResource.DownloadByVersionName", + "FileResource.DownloadByVersion", "Client.Create", "Client.Search", @@ -49,7 +49,7 @@ "FileResource.GetById", "FileResource.Search", "FileResource.Download", - "FileResource.DownloadByVersionName", + "FileResource.DownloadByVersion", "Participant.Create", "Participant.Search", diff --git a/src/api/client/client.controller.ts b/src/api/client/client.controller.ts index 0185afe..e9c5a99 100644 --- a/src/api/client/client.controller.ts +++ b/src/api/client/client.controller.ts @@ -65,7 +65,21 @@ export class ClientController extends BaseController { ErrorHandler.throwNotFoundError('Api client with id ' + id.toString() + ' cannot be found!'); } const message = 'Api client retrieved successfully!'; - ResponseHandler.success(request, response, message, 200, record); + ResponseHandler.success(request, response, message, 200, { Client: record }); + } catch (error) { + ResponseHandler.handleError(request, response, error); + } + }; + + getByApiKey = async (request: express.Request, response: express.Response) => { + try { + const currentClient = request.currentClient; + const record = await this._service.getByClientCode(currentClient?.Code); + if (record === null) { + ErrorHandler.throwNotFoundError('Api client with code ' + currentClient?.Code?.toString() + ' cannot be found!'); + } + const message = 'Api client retrieved successfully!'; + ResponseHandler.success(request, response, message, 200, { Client: record }); } catch (error) { ResponseHandler.handleError(request, response, error); } diff --git a/src/api/client/client.routes.ts b/src/api/client/client.routes.ts index eeac341..5774372 100644 --- a/src/api/client/client.routes.ts +++ b/src/api/client/client.routes.ts @@ -21,8 +21,10 @@ export const register = (app: express.Application): void => { router.get('/search', authenticator.authenticateUser, controller.search); router.get('/:id', authenticator.authenticateUser, controller.getById); + router.get('/', authenticator.authenticateClient, controller.getByApiKey); router.put('/:id', authenticator.authenticateUser, controller.update); router.delete('/:id', authenticator.authenticateUser, controller.delete); + app.use('/api/v1/clients', router); }; diff --git a/src/api/general/file.resource/file.resource.controller.ts b/src/api/general/file.resource/file.resource.controller.ts index 361080a..a2cf51f 100644 --- a/src/api/general/file.resource/file.resource.controller.ts +++ b/src/api/general/file.resource/file.resource.controller.ts @@ -11,7 +11,6 @@ import { FileResourceCreateModel } from '../../../domain.types/general/file.reso import { FileUtils } from '../../../common/utilities/file.utils'; import { Loader } from '../../../startup/loader'; import { StorageService } from '../../../modules/storage/storage.service'; -import { IFileStorageService } from '../../../modules/storage/interfaces/file.storage.service.interface'; import { FileResourceMetadata } from '../../../domain.types/general/file.resource/file.resource.types'; import { Authenticator } from '../../../auth/authenticator'; import path from 'path'; @@ -58,7 +57,7 @@ export class FileResourceController extends BaseController { filename = filename + '_' + timestamp + '.' + ext; var storageKey = 'uploaded/' + dateFolder + '/' + filename; - var key = await this._storageService.upload(request, storageKey); + var key = await this._storageService.upload(storageKey, request); if (!key) { ErrorHandler.throwInternalServerError(`Unable to upload the file!`); } @@ -166,9 +165,9 @@ export class FileResourceController extends BaseController { } }; - downloadByVersionName = async (request: express.Request, response: express.Response): Promise => { + DownloadByVersion = async (request: express.Request, response: express.Response): Promise => { try { - request.context = 'FileResource.DownloadByVersionName'; + request.context = 'FileResource.DownloadByVersion'; const metadata = await this._validator.getByVersionName(request); var resource = await this._service.getById(metadata.ResourceId); @@ -184,7 +183,7 @@ export class FileResourceController extends BaseController { console.log(`Download request for Resource Id:: ${metadata.ResourceId} and Version:: ${metadata.Version}`); - const localDestination = await this._service.downloadByVersionName( + const localDestination = await this._service.DownloadByVersion( metadata.ResourceId, metadata.Version); diff --git a/src/api/general/file.resource/file.resource.routes.ts b/src/api/general/file.resource/file.resource.routes.ts index 008da0c..e30ecc5 100644 --- a/src/api/general/file.resource/file.resource.routes.ts +++ b/src/api/general/file.resource/file.resource.routes.ts @@ -15,7 +15,7 @@ export const register = (app: express.Application): void => { router.get('/:id', authenticator.authenticateUser, controller.getById); router.delete('/:id', authenticator.authenticateUser, controller.delete); - router.get('/:id/download-by-version-name/:version', controller.downloadByVersionName); + router.get('/:id/download-by-version-name/:version', controller.DownloadByVersion); app.use('/api/v1/file-resources', router); }; diff --git a/src/database/mappers/awards/participant.group.mapper.ts b/src/database/mappers/awards/participant.group.mapper.ts index 2373a27..81368af 100644 --- a/src/database/mappers/awards/participant.group.mapper.ts +++ b/src/database/mappers/awards/participant.group.mapper.ts @@ -15,6 +15,7 @@ export class ParticipantGroupMapper { const client = ClientMapper.toResponseDto(group.Client); const dto: ParticipantGroupResponseDto = { id : group.id, + ReferenceId : group.ReferenceId, Client : client, Name : group.Name, Description : group.Description, diff --git a/src/database/models/awards/participant.group.model.ts b/src/database/models/awards/participant.group.model.ts index 1c64749..b59c0ae 100644 --- a/src/database/models/awards/participant.group.model.ts +++ b/src/database/models/awards/participant.group.model.ts @@ -23,6 +23,9 @@ export class ParticipantGroup { @PrimaryGeneratedColumn('uuid') id : string; + @Column({ type: 'varchar', length: 256, nullable: true }) + ReferenceId : string; //This is id of the group in external system + @ManyToOne(() => Client, { nullable: true }) @JoinColumn() Client : Client; diff --git a/src/database/services/awards/participant.group.service.ts b/src/database/services/awards/participant.group.service.ts index d27af58..49a9ff2 100644 --- a/src/database/services/awards/participant.group.service.ts +++ b/src/database/services/awards/participant.group.service.ts @@ -39,6 +39,7 @@ export class ParticipantGroupService extends BaseService { const client = await this.getClient(createModel.ClientId); const badge = this._groupRepository.create({ Client : client, + ReferenceId : createModel.ReferenceId, Name : createModel.Name, Description : createModel.Description, ImageUrl : createModel.ImageUrl, @@ -48,7 +49,7 @@ export class ParticipantGroupService extends BaseService { //Keep group context for this participant group const context = this._contextRepository.create({ Type : ContextType.Group, - ReferenceId : record.id, + ReferenceId : record.ReferenceId, Group : record, }); const contextRecord = await this._contextRepository.save(context); @@ -228,6 +229,7 @@ export class ParticipantGroupService extends BaseService { }, select : { id : true, + ReferenceId : true, Client : { id : true, Name : true, diff --git a/src/database/services/general/file.resource.service.ts b/src/database/services/general/file.resource.service.ts index a446345..10e29fd 100644 --- a/src/database/services/general/file.resource.service.ts +++ b/src/database/services/general/file.resource.service.ts @@ -17,11 +17,12 @@ import { FileResourceDto } from '../../../domain.types/general/file.resource/fil import { FileResourceMetadata } from '../../../domain.types/general/file.resource/file.resource.types'; import path from 'path'; import { Helper } from '../../../common/helper'; -import { AWSS3FileStorageService } from '../../../modules/storage/providers/aws.s3.file.storage.service'; import { FileResourceVersion } from '../../../database/models/general/file.resource.version.model'; import { FileResourceUploadDomainModel } from '../../../domain.types/general/file.resource/file.resource.domain.model'; import { ConfigurationManager } from '../../../config/configuration.manager'; import { TimeUtils } from '../../../common/utilities/time.utils'; +import { StorageService } from '../../../modules/storage/storage.service'; +import { Loader } from '../../../startup/loader'; /////////////////////////////////////////////////////////////////////////////////////////////// @@ -29,7 +30,7 @@ export class FileResourceService { //#region Models - _storageService: AWSS3FileStorageService = new AWSS3FileStorageService(); + _storageService: StorageService = null; _fileResourceRepository : Repository = Source.getRepository(FileResource); @@ -37,6 +38,10 @@ export class FileResourceService { _userRepository : Repository = Source.getRepository(User); + constructor() { + this._storageService = Loader.Container.resolve(StorageService); + } + //#endregion //#region Publics @@ -249,8 +254,8 @@ export class FileResourceService { }; uploadLocal = async ( + storageKey: string, sourceLocation: string, - storageLocation: string, isPublicResource: boolean ): Promise => { @@ -259,15 +264,19 @@ export class FileResourceService { console.log('Source file location does not exist!'); } - var storageKey:string = null; - var existingStorageKey = await this._storageService.exists(storageLocation); + var existingStorageKey = await this._storageService.exists(storageKey); if (existingStorageKey !== undefined && existingStorageKey !== null) { storageKey = existingStorageKey; } else { - storageKey = await this._storageService.upload(sourceLocation, storageLocation); + storageKey = await this._storageService.uploadLocally(storageKey, sourceLocation); } + if(!storageKey) { + console.log('Unable to upload file to storage!'); + return null; + } + var stats = fs.statSync(sourceLocation); var filename = path.basename(sourceLocation); @@ -281,7 +290,6 @@ export class FileResourceService { StorageKey : storageKey, }; - var domainModel: FileResourceUploadDomainModel = { FileMetadata : metadata, StorageKey : metadata.StorageKey, @@ -337,7 +345,7 @@ export class FileResourceService { return FileResourceMapper.toFileVersionDto(version); }; - downloadByVersionName = async (resourceId: string, versionName: string): Promise => { + DownloadByVersion = async (resourceId: string, versionName: string): Promise => { var downloadFolderPath = await this.generateDownloadFolderPath(); //var versionMetadata = await this._fileResourceRepo.getVersionByVersionName(resourceId, versionName); diff --git a/src/domain.types/awards/participant.group.domain.types.ts b/src/domain.types/awards/participant.group.domain.types.ts index 81e083f..de9ff66 100644 --- a/src/domain.types/awards/participant.group.domain.types.ts +++ b/src/domain.types/awards/participant.group.domain.types.ts @@ -10,6 +10,7 @@ import { export interface ParticipantGroupCreateModel { ClientId : uuid; + ReferenceId? : uuid; Name : string; Description? : string; ImageUrl : string; @@ -18,12 +19,14 @@ export interface ParticipantGroupCreateModel { export interface ParticipantGroupUpdateModel { ClientId : uuid; Name? : string; + ReferenceId? : uuid; Description? : string; ImageUrl? : string; } export interface ParticipantGroupResponseDto { - id : uuid; + id : uuid; + ReferenceId: uuid; Client: { id : uuid; Name: string; @@ -47,6 +50,7 @@ export interface ParticipantGroupResponseDto { export interface ParticipantGroupSearchFilters extends BaseSearchFilters { ClientId? : uuid; + ReferenceId? : uuid; Name? : string; ParticipantId? : uuid; } diff --git a/src/modules/storage/interfaces/file.storage.service.interface.ts b/src/modules/storage/interfaces/file.storage.service.interface.ts index 3c49e46..d510392 100644 --- a/src/modules/storage/interfaces/file.storage.service.interface.ts +++ b/src/modules/storage/interfaces/file.storage.service.interface.ts @@ -3,11 +3,11 @@ export interface IFileStorageService { exists(storageKey: string): Promise; - upload(inputStream, storageKey: string): Promise; + upload(storageKey: string, inputStream): Promise; download(storageKey: string, localFilePath: string): Promise; - uploadLocally(storageKey: string, localFilePath?: string): Promise; + uploadLocally(storageKey: string, localFilePath?: string): Promise; downloadLocally(storageKey: string, localFilePath: string): Promise; diff --git a/src/modules/storage/providers/aws.s3.file.storage.service.ts b/src/modules/storage/providers/aws.s3.file.storage.service.ts index e27a22a..ee58d09 100644 --- a/src/modules/storage/providers/aws.s3.file.storage.service.ts +++ b/src/modules/storage/providers/aws.s3.file.storage.service.ts @@ -28,7 +28,7 @@ export class AWSS3FileStorageService implements IFileStorageService { } }; - upload = async (inputStream: any, storageKey: string): Promise => { + upload = async (storageKey: string, inputStream: any): Promise => { try { const fileContent = fs.readFileSync(inputStream); var s3 = this.getS3Client(); @@ -43,10 +43,11 @@ export class AWSS3FileStorageService implements IFileStorageService { } catch (error) { logger.error(error.message); + return null; } }; - uploadLocally = async (storageKey: string, localFilePath: string): Promise => { + uploadLocally = async (storageKey: string, localFilePath: string): Promise => { try { const fileContent = fs.readFileSync(localFilePath); @@ -65,6 +66,7 @@ export class AWSS3FileStorageService implements IFileStorageService { } catch (error) { logger.error(error.message); + return null; } }; diff --git a/src/modules/storage/providers/custom.file.storage.service.ts b/src/modules/storage/providers/custom.file.storage.service.ts index 7d43516..39db952 100644 --- a/src/modules/storage/providers/custom.file.storage.service.ts +++ b/src/modules/storage/providers/custom.file.storage.service.ts @@ -28,7 +28,7 @@ export class CustomFileStorageService implements IFileStorageService { } }; - upload = async (inputStream: any, storageKey: string): Promise => { + upload = async (storageKey: string, inputStream: any): Promise => { return new Promise((resolve, reject) => { try { var storagePath = FileUtils.getStoragePath(); @@ -46,13 +46,14 @@ export class CustomFileStorageService implements IFileStorageService { }); } catch (error) { + logger.error("Unable to create file resource!"); logger.error(error.message); - reject("Unable to create file resource!"); + reject(null); } }); }; - uploadLocally = async (storageKey: string, localFilePath: string): Promise => { + uploadLocally = async (storageKey: string, localFilePath: string): Promise => { try { const fileContent = fs.readFileSync(localFilePath); const location = path.join(this._storagePath, storageKey); diff --git a/src/modules/storage/storage.service.ts b/src/modules/storage/storage.service.ts index aae9a2a..53781e9 100644 --- a/src/modules/storage/storage.service.ts +++ b/src/modules/storage/storage.service.ts @@ -12,15 +12,15 @@ export class StorageService { return await this._storageService.exists(storageKey); } - upload = async (inputStream, storageKey: string): Promise => { - return await this._storageService.upload(inputStream, storageKey); + upload = async (storageKey: string, inputStream): Promise => { + return await this._storageService.upload(storageKey, inputStream); } download = async (storageKey: string, localFilePath?: string): Promise => { return await this._storageService.download(storageKey, localFilePath); } - uploadLocally = async (storageKey: string, localFilePath?: string): Promise => { + uploadLocally = async (storageKey: string, localFilePath?: string): Promise => { return await this._storageService.uploadLocally(storageKey, localFilePath); } diff --git a/src/startup/seeder.ts b/src/startup/seeder.ts index 678edd4..87f5d54 100644 --- a/src/startup/seeder.ts +++ b/src/startup/seeder.ts @@ -201,7 +201,7 @@ export class Seeder { return; } - var cloudStoragePath = 'assets/images/stock.badge.images/'; + var destinationStoragePath = 'assets/images/stock.badge.images/'; var sourceFilePath = path.join(process.cwd(), "./assets/images/stock.badge.images/"); var files = fs.readdirSync(sourceFilePath); @@ -211,13 +211,17 @@ export class Seeder { for await (const fileName of imageFiles) { - var sourceFileLocation = path.join(sourceFilePath, fileName); - var storageFileLocation = cloudStoragePath + fileName; + var sourceLocation = path.join(sourceFilePath, fileName); + var storageKey = destinationStoragePath + fileName; var uploaded = await this._fileResourceService.uploadLocal( - sourceFileLocation, - storageFileLocation, + storageKey, + sourceLocation, true); + + if (!uploaded) { + continue; + } var domainModel: BadgeStockImageDomainModel = { Code : fileName.replace('.png', ''), From 745fa5b18f556f242c891975ca18a02a7f59f19e Mon Sep 17 00:00:00 2001 From: Kiran Kharade Date: Mon, 12 Jun 2023 12:36:20 +0530 Subject: [PATCH 32/66] Reverting response for some client controller actions --- src/api/client/client.controller.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/client/client.controller.ts b/src/api/client/client.controller.ts index e9c5a99..85b6235 100644 --- a/src/api/client/client.controller.ts +++ b/src/api/client/client.controller.ts @@ -65,7 +65,7 @@ export class ClientController extends BaseController { ErrorHandler.throwNotFoundError('Api client with id ' + id.toString() + ' cannot be found!'); } const message = 'Api client retrieved successfully!'; - ResponseHandler.success(request, response, message, 200, { Client: record }); + ResponseHandler.success(request, response, message, 200, record); } catch (error) { ResponseHandler.handleError(request, response, error); } @@ -79,7 +79,7 @@ export class ClientController extends BaseController { ErrorHandler.throwNotFoundError('Api client with code ' + currentClient?.Code?.toString() + ' cannot be found!'); } const message = 'Api client retrieved successfully!'; - ResponseHandler.success(request, response, message, 200, { Client: record }); + ResponseHandler.success(request, response, message, 200, record); } catch (error) { ResponseHandler.handleError(request, response, error); } From 778fda529133ac51c3600474f10a2191ab887b2c Mon Sep 17 00:00:00 2001 From: Kiran Kharade Date: Thu, 15 Jun 2023 13:03:21 +0530 Subject: [PATCH 33/66] Fixed issues with calculate contnuity - applying unique key check. (cherry picked from commit 55a1d490202e33282d24beb1ecd9d4de63b5df9b) --- .../implementation/data.processor.ts | 83 +++++++++++++++---- 1 file changed, 67 insertions(+), 16 deletions(-) diff --git a/src/modules/processor/providers/implementation/data.processor.ts b/src/modules/processor/providers/implementation/data.processor.ts index aa27cba..e56f048 100644 --- a/src/modules/processor/providers/implementation/data.processor.ts +++ b/src/modules/processor/providers/implementation/data.processor.ts @@ -145,32 +145,83 @@ export class DataProcessorr implements IDataProcessor { //#region Private methods getConsecutiveOccurrences = ( - records: any[], predicate: PredicateType, options: ContinuityInputParams) => { - let count = 0; + records: any[], + predicate: PredicateType, + options: ContinuityInputParams, + uniqueKeys = true) => { + const foundBundles = []; var bundle = []; const numOccurrences: number = options.ContinuityCount; const valueName = 'value'; // Pl. check this again... - for (let i = 0; i < records.length; i++) { - if (predicate( - records[i], - valueName, - options.Operator, - options.Value, - options.SecondaryValue)) { - count++; - bundle.push(records[i]); - if (count === numOccurrences) { - foundBundles.push(bundle); + //Sort records in ascending order of the key + var sortedRecords = records.sort((a, b) => { return a.key - b.key; }); + + if (!uniqueKeys) { + + let count = 0; + + for (let i = 0; i < sortedRecords.length; i++) { + + const record = sortedRecords[i]; + + if (predicate( + record, + valueName, + options.Operator, + options.Value, + options.SecondaryValue)) { + + count++; + bundle.push(record); + + if (count === numOccurrences) { + foundBundles.push(bundle); + count = 0; + bundle = []; + } + + } else { count = 0; bundle = []; } - } else { - count = 0; - bundle = []; + } + } else { + var bundleKeySet = new Set(); + + for (let i = 0; i < sortedRecords.length; i++) { + + const record = sortedRecords[i]; + const recordKey = record.key; + + if (predicate( + record, + valueName, + options.Operator, + options.Value, + options.SecondaryValue)) { + + if (bundleKeySet.has(recordKey)) { + continue; + } + + bundleKeySet.add(recordKey); + bundle.push(record); + + if (bundleKeySet.size === numOccurrences) { + foundBundles.push(bundle); + bundle = []; + bundleKeySet = new Set(); + } + } + else { + bundle = []; + bundleKeySet = new Set(); + } } } + return foundBundles; }; From 08ccdf9c119fc14f6fc4be68959a2e4870829c4d Mon Sep 17 00:00:00 2001 From: Vaibhav Dalal Date: Thu, 15 Jun 2023 15:36:37 +0530 Subject: [PATCH 34/66] Added uat-ci-cd workflow --- .github/workflows/uat-ci-cd.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .github/workflows/uat-ci-cd.yml diff --git a/.github/workflows/uat-ci-cd.yml b/.github/workflows/uat-ci-cd.yml new file mode 100644 index 0000000..e69de29 From 403bc3d0e17c756eda954e0ac31709bea609b779 Mon Sep 17 00:00:00 2001 From: Vaibhav Dalal Date: Thu, 15 Jun 2023 15:41:34 +0530 Subject: [PATCH 35/66] Added uat-ci-cd workflow --- .github/workflows/uat-ci-cd.yml | 153 ++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) diff --git a/.github/workflows/uat-ci-cd.yml b/.github/workflows/uat-ci-cd.yml index e69de29..ba90329 100644 --- a/.github/workflows/uat-ci-cd.yml +++ b/.github/workflows/uat-ci-cd.yml @@ -0,0 +1,153 @@ +# This workflow will trigger pull requests and apply a label based on the +# paths that are modified in the pull request. +# +# To use this workflow, you will need to set up a .github/labeler.yml +# file with configuration. For more information, see: +# https://github.com/actions/labeler + +name: UAT-CI-CD + +# Controls when the workflow will run +on: + # Triggers the workflow on push events but only for the develop branch + + pull_request: + branches: main + + push: + branches: + - 'release/**' + - '!release/aha**' # excludes master + +jobs: + CodeScan-ESLint: + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Lint Code Base + uses: docker://ghcr.io/github/super-linter:latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + LINTER_RULES_PATH: / + TYPESCRIPT_ES_CONFIG_FILE: .eslintrc.json + VALIDATE_TYPESCRIPT_ES: true + VALIDATE_ALL_CODEBASE: false + DEFAULT_BRANCH: main + + Label_Checks: + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Check labels + if: ${{ github.event_name == 'pull_request' }} + uses: docker://agilepathway/pull-request-label-checker:latest + with: + one_of: major,minor,patch + repo_token: ${{ secrets.GITHUB_TOKEN }} + + Deploy-ECS: + if: ${{ github.event_name == 'push' }} + environment: uat + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Declare some variables + id: vars + shell: bash + run: | + echo "branch=$(echo ${GITHUB_REF#refs/heads/} | sed "s/\\//-/g")" >> $GITHUB_OUTPUT + echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT + echo "repo_name=$(echo "$GITHUB_REPOSITORY" | awk -F / '{print $2}')" >> $GITHUB_OUTPUT + + - name: Another step + run: | + echo "Branch: ${{ steps.vars.outputs.branch }}" + echo "Sha: ${{ steps.vars.outputs.sha_short }}" + echo "Repo: ${{ steps.vars.outputs.repo_name }}" + + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v1 + + - name: Cache Docker layers + uses: actions/cache@v3 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Build and push + id: docker_build + uses: docker/build-push-action@v3 + with: + context: ./ + file: ./Dockerfile + builder: ${{ steps.buildx.outputs.name }} + push: true + tags: ${{ steps.login-ecr.outputs.registry }}/reancare-service-dev-uat:${{ steps.vars.outputs.branch }}_${{ steps.vars.outputs.sha_short }} + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache + + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} + + - name: Download task definition + run: | + aws ecs describe-task-definition --task-definition ${{ secrets.TASK_DEFINTION_NAME }} \ + --query taskDefinition > task-definition.json + + - name: New image ID in the Amazon ECS task definition + id: task-def + uses: aws-actions/amazon-ecs-render-task-definition@v1 + with: + task-definition: task-definition.json + container-name: default + image: ${{ steps.login-ecr.outputs.registry }}/reancare-service-dev-uat:${{ steps.vars.outputs.branch }}_${{ steps.vars.outputs.sha_short }} + + - name: Deploy Amazon ECS task definition + uses: aws-actions/amazon-ecs-deploy-task-definition@v1 + with: + task-definition: ${{ steps.task-def.outputs.task-definition }} + wait-for-service-stability: true + + - name: Task Definition Variable + id: taskdefintionvar + shell: bash + run: | + # echo "::set-output name=task_definition_arn::$(aws ecs describe-task-definition --task-definition ${{ secrets.TASK_DEFINTION_NAME }} | jq '.[] | .taskDefinitionArn')" + echo "task_definition_arn=$(aws ecs describe-task-definition --task-definition ${{ secrets.TASK_DEFINTION_NAME }} | jq '.[] | .taskDefinitionArn')" >> $GITHUB_OUTPUT + + - name: Task Defintion ARN + run: | + echo "Task Defintion: ${{ steps.taskdefintionvar.outputs.task_definition_arn }}" + + - name: Deploy Amazon ECS task definition using Duplo API + uses: fjogeleit/http-request-action@master + with: + url: 'https://reanfoundation.duplocloud.net/subscriptions/${{ secrets.DUPLO_ID }}/UpdateEcsService' + method: 'POST' + data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "${{ secrets.SERVICE_NAME }}","Replicas":1, "HealthCheckGracePeriodSeconds": 1200}' + bearerToken: ${{ secrets.DUPLOCLOUD_TOKEN }} \ No newline at end of file From 83f9816163780c92fabe02696294a90c0743bd54 Mon Sep 17 00:00:00 2001 From: Vaibhav Dalal Date: Thu, 15 Jun 2023 16:06:44 +0530 Subject: [PATCH 36/66] Updated uat-ci-cd.yml file --- .github/workflows/uat-ci-cd.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/uat-ci-cd.yml b/.github/workflows/uat-ci-cd.yml index ba90329..2a24890 100644 --- a/.github/workflows/uat-ci-cd.yml +++ b/.github/workflows/uat-ci-cd.yml @@ -107,7 +107,7 @@ jobs: file: ./Dockerfile builder: ${{ steps.buildx.outputs.name }} push: true - tags: ${{ steps.login-ecr.outputs.registry }}/reancare-service-dev-uat:${{ steps.vars.outputs.branch }}_${{ steps.vars.outputs.sha_short }} + tags: ${{ steps.login-ecr.outputs.registry }}/awards-service:${{ steps.vars.outputs.branch }}_${{ steps.vars.outputs.sha_short }} cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,dest=/tmp/.buildx-cache @@ -125,7 +125,7 @@ jobs: with: task-definition: task-definition.json container-name: default - image: ${{ steps.login-ecr.outputs.registry }}/reancare-service-dev-uat:${{ steps.vars.outputs.branch }}_${{ steps.vars.outputs.sha_short }} + image: ${{ steps.login-ecr.outputs.registry }}/awards-service:${{ steps.vars.outputs.branch }}_${{ steps.vars.outputs.sha_short }} - name: Deploy Amazon ECS task definition uses: aws-actions/amazon-ecs-deploy-task-definition@v1 From 9f13f3c0f485808ef201a974a18583deac01e03d Mon Sep 17 00:00:00 2001 From: Vaibhav Dalal Date: Thu, 15 Jun 2023 17:24:22 +0530 Subject: [PATCH 37/66] Added DNS prefix in uat-cicd --- .github/workflows/uat-ci-cd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/uat-ci-cd.yml b/.github/workflows/uat-ci-cd.yml index 2a24890..bad1fc0 100644 --- a/.github/workflows/uat-ci-cd.yml +++ b/.github/workflows/uat-ci-cd.yml @@ -149,5 +149,5 @@ jobs: with: url: 'https://reanfoundation.duplocloud.net/subscriptions/${{ secrets.DUPLO_ID }}/UpdateEcsService' method: 'POST' - data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "${{ secrets.SERVICE_NAME }}","Replicas":1, "HealthCheckGracePeriodSeconds": 1200}' + data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "${{ secrets.SERVICE_NAME }}","Replicas":1, "HealthCheckGracePeriodSeconds": 1200, "DnsPrfx": ""}' bearerToken: ${{ secrets.DUPLOCLOUD_TOKEN }} \ No newline at end of file From 8fde223778359b0328dcdef08b4edc54c75fa359 Mon Sep 17 00:00:00 2001 From: vinay-debug <84920398+vinay-debug@users.noreply.github.com> Date: Fri, 16 Jun 2023 09:19:10 +0530 Subject: [PATCH 38/66] Changes medication from any to all --- .../implementation/data.extractors/medication.data.extractor.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/processor/providers/implementation/data.extractors/medication.data.extractor.ts b/src/modules/processor/providers/implementation/data.extractors/medication.data.extractor.ts index f32b8a6..7d690f2 100644 --- a/src/modules/processor/providers/implementation/data.extractors/medication.data.extractor.ts +++ b/src/modules/processor/providers/implementation/data.extractors/medication.data.extractor.ts @@ -21,7 +21,7 @@ export class MedicationDataExtractor implements IExtractor { const filters = inputParams.Filters ?? {}; var samplingMethod = filters['SamplingMethod'] as DataSamplingMethod; if (!samplingMethod) { - samplingMethod = DataSamplingMethod.Any; + samplingMethod = DataSamplingMethod.All; } const records = await this._medicationRepository.find({ From 4aa27da9796fed77d750d4263b42a77b87854264 Mon Sep 17 00:00:00 2001 From: vinay-debug <84920398+vinay-debug@users.noreply.github.com> Date: Fri, 16 Jun 2023 09:19:30 +0530 Subject: [PATCH 39/66] Removed eslint error --- .../engine.execution/rule.converter.ts | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/modules/engine.execution/rule.converter.ts b/src/modules/engine.execution/rule.converter.ts index 6c1f9f0..616c4a0 100644 --- a/src/modules/engine.execution/rule.converter.ts +++ b/src/modules/engine.execution/rule.converter.ts @@ -1,7 +1,7 @@ import { CompositionOperator, LogicalOperator, OperatorType } from '../../domain.types/engine/engine.types'; import { CCondition, - CRule} from './execution.types'; + CRule } from './execution.types'; export class RuleConverter { @@ -10,30 +10,30 @@ export class RuleConverter { var condition = rule.RootCondition as CCondition; var decision: any = { - conditions: RuleConverter.addCompositeCondition(condition), - event: { - type: rule.Action?.ActionType, - params: rule.Action?.OutputParams + conditions : RuleConverter.addCompositeCondition(condition), + event : { + type : rule.Action?.ActionType, + params : rule.Action?.OutputParams } }; return decision; - } + }; private static addCompositeCondition(condition: CCondition) { - if(condition.OperatorType !== OperatorType.Composition) { + if (condition.OperatorType !== OperatorType.Composition) { throw new Error('Expecting a composite condition!'); } var list = RuleConverter.addChildrenConditions(condition); if (condition.Operator == CompositionOperator.And) { return { all : list - } + }; } else { return { any : list - } + }; } } @@ -58,14 +58,14 @@ export class RuleConverter { } var operator = RuleConverter.translateLogicalOperator(condition.Operator as LogicalOperator); return { - fact: condition.Fact, - operator: operator, - value: condition.Value - } + fact : condition.Fact, + operator : operator, + value : condition.Value + }; } private static translateLogicalOperator(operator: LogicalOperator) { - switch(operator) { + switch (operator) { case LogicalOperator.Equal: { return 'equal'; From 5ab5d5ab16c835abbeb391aeada27368e6e0db79 Mon Sep 17 00:00:00 2001 From: vinay-debug <84920398+vinay-debug@users.noreply.github.com> Date: Mon, 19 Jun 2023 02:46:12 +0530 Subject: [PATCH 40/66] Corrected the postman collection --- .../awards service.postman_collection.json | 254 +++--------------- 1 file changed, 41 insertions(+), 213 deletions(-) diff --git a/postman/awards service.postman_collection.json b/postman/awards service.postman_collection.json index b33a786..0113d2e 100644 --- a/postman/awards service.postman_collection.json +++ b/postman/awards service.postman_collection.json @@ -1,9 +1,9 @@ { "info": { - "_postman_id": "29ce7b9b-655c-45f2-833c-2430e2143603", + "_postman_id": "f1b0e9a5-9223-4ad2-972c-9446fcab3430", "name": "Awards service", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "11713506" + "_exporter_id": "15905052" }, "item": [ { @@ -680,7 +680,7 @@ "exec": [ "try {\r", " var jsonRes = pm.response.json();\r", - " pm.environment.set(\"HEALTH_JOURNEY_EVENT_TYPE_ID\", jsonRes.Data.id);\r", + " pm.environment.set(\"VITAL_EVENT_TYPE_ID\", jsonRes.Data.id);\r", "}\r", "catch (error) {\r", " console.log(error.message);\r", @@ -733,7 +733,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"Name\": \"Health Journey\",\r\n \"Description\": \"This event is triggered when a patient marks health journey task as done\"\r\n}\r\n" + "raw": "{\r\n \"Name\": \"Vital\",\r\n \"Description\": \"This event is triggered when a patient record vitals regularily\"\r\n}\r\n" }, "url": { "raw": "{{BASE_URL}}/engine/event-types", @@ -750,23 +750,30 @@ "response": [] }, { - "name": "Search all event types", + "name": "Create mental health event type", "event": [ { "listen": "test", "script": { "exec": [ + "try {\r", + " var jsonRes = pm.response.json();\r", + " pm.environment.set(\"MENTAL_HEALTH_EVENT_TYPE_ID\", jsonRes.Data.id);\r", + "}\r", + "catch (error) {\r", + " console.log(error.message);\r", + "}\r", "\r", "pm.test(\"Request is successfull\", function () {\r", - " pm.response.to.have.status(200);\r", + " pm.response.to.have.status(201);\r", " var jsonRes = pm.response.json();\r", " pm.expect(jsonRes.Status).to.eql('success');\r", "});\r", "\r", - "pm.test(\"All event types are returned\", function () {\r", + "pm.test(\"Event type is created\", function () {\r", " var jsonRes = pm.response.json();\r", - " pm.expect(jsonRes.Data).to.have.property('Items');\r", - " pm.expect(jsonRes.Data.Items.length).greaterThan(0);\r", + " pm.expect(jsonRes.Data).to.have.property('Name');\r", + " pm.expect(jsonRes.Data.Name).to.not.be.null;\r", "});\r", "" ], @@ -784,7 +791,7 @@ } ], "request": { - "method": "GET", + "method": "POST", "header": [ { "key": "Content-Type", @@ -802,15 +809,18 @@ "type": "text" } ], + "body": { + "mode": "raw", + "raw": "{\r\n \"Name\": \"MentalHealth\",\r\n \"Description\": \"This event is triggered when a patient marks medication consumption as taken or missed\"\r\n}\r\n" + }, "url": { - "raw": "{{BASE_URL}}/engine/event-types/search", + "raw": "{{BASE_URL}}/engine/event-types", "host": [ "{{BASE_URL}}" ], "path": [ "engine", - "event-types", - "search" + "event-types" ] }, "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." @@ -818,30 +828,23 @@ "response": [] }, { - "name": "Create mental health event type", + "name": "Search all event types", "event": [ { "listen": "test", "script": { "exec": [ - "try {\r", - " var jsonRes = pm.response.json();\r", - " pm.environment.set(\"MENTAL_HEALTH_EVENT_TYPE_ID\", jsonRes.Data.id);\r", - "}\r", - "catch (error) {\r", - " console.log(error.message);\r", - "}\r", "\r", "pm.test(\"Request is successfull\", function () {\r", - " pm.response.to.have.status(201);\r", + " pm.response.to.have.status(200);\r", " var jsonRes = pm.response.json();\r", " pm.expect(jsonRes.Status).to.eql('success');\r", "});\r", "\r", - "pm.test(\"Event type is created\", function () {\r", + "pm.test(\"All event types are returned\", function () {\r", " var jsonRes = pm.response.json();\r", - " pm.expect(jsonRes.Data).to.have.property('Name');\r", - " pm.expect(jsonRes.Data.Name).to.not.be.null;\r", + " pm.expect(jsonRes.Data).to.have.property('Items');\r", + " pm.expect(jsonRes.Data.Items.length).greaterThan(0);\r", "});\r", "" ], @@ -859,7 +862,7 @@ } ], "request": { - "method": "POST", + "method": "GET", "header": [ { "key": "Content-Type", @@ -877,18 +880,15 @@ "type": "text" } ], - "body": { - "mode": "raw", - "raw": "{\r\n \"Name\": \"MentalHealth\",\r\n \"Description\": \"This event is triggered when a patient marks medication consumption as taken or missed\"\r\n}\r\n" - }, "url": { - "raw": "{{BASE_URL}}/engine/event-types", + "raw": "{{BASE_URL}}/engine/event-types/search", "host": [ "{{BASE_URL}}" ], "path": [ "engine", - "event-types" + "event-types", + "search" ] }, "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." @@ -2177,7 +2177,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"ReferenceId\": \"{{REFERENCE_ID}}\",\r\n \"Prefix\": \"Mr.\",\r\n \"FirstName\": \"Sachin\",\r\n \"LastName\": \"Tendulkar\",\r\n \"Gender\": \"Male\",\r\n \"BirthDate\": \"1974-04-24\",\r\n \"Email\": \"sachin.tendulkar@gmail.com\",\r\n \"CountryCode\": \"+91\",\r\n \"Phone\": \"1234567890\",\r\n \"OnboardingDate\": \"{{TODAY}}\"\r\n}" + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"ReferenceId\": \"{{REFERENCE_ID}}\",\r\n \"Prefix\": \"Mr.\",\r\n \"FirstName\": \"Sachin\",\r\n \"LastName\": \"Tendulkar\",\r\n \"Gender\": \"Male\",\r\n \"BirthDate\": \"1974-04-24\",\r\n \"Email\": \"sachin.tendulkar@gmail.com\",\r\n \"CountryCode\": \"+91\",\r\n \"Phone\": \"1234567891\",\r\n \"OnboardingDate\": \"{{TODAY}}\"\r\n}" }, "url": { "raw": "{{BASE_URL}}/participants", @@ -2733,7 +2733,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Medication 7-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient takes medication regularly for 7 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{MEDICATION_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract medication data\",\r\n \"Description\": \"Extract medication data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract medication data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Medication\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"Any\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting medication data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:Medication\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Medication 7-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient takes medication regularly for 7 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{MEDICATION_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract medication data\",\r\n \"Description\": \"Extract medication data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract medication data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Medication\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"All\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting medication data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:Medication\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" }, "url": { "raw": "{{BASE_URL}}/engine/schema", @@ -3755,7 +3755,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Medication 15-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient takes medication regularly for 15 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{MEDICATION_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract medication data\",\r\n \"Description\": \"Extract medication data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract medication data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Medication\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"Any\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting medication data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:Medication\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Medication 15-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient takes medication regularly for 15 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{MEDICATION_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract medication data\",\r\n \"Description\": \"Extract medication data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract medication data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Medication\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"All\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting medication data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:Medication\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" }, "url": { "raw": "{{BASE_URL}}/engine/schema", @@ -4777,7 +4777,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Medication 30-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient takes medication regularly for 30 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{MEDICATION_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract medication data\",\r\n \"Description\": \"Extract medication data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract medication data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Medication\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"Any\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting medication data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:Medication\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Medication 30-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient takes medication regularly for 30 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{MEDICATION_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract medication data\",\r\n \"Description\": \"Extract medication data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract medication data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Medication\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"All\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting medication data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:Medication\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" }, "url": { "raw": "{{BASE_URL}}/engine/schema", @@ -12393,7 +12393,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Vital Monitoring 7-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient monitor body vitals for 7 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{VITAL_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract vital data\",\r\n \"Description\": \"Extract vital data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract vital data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Vital\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"Any\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting vital data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:Vital\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Vital Monitoring 7-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient monitor body vitals for 7 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{VITAL_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract vital data\",\r\n \"Description\": \"Extract vital data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract vital data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Vital\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"All\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting vital data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:Vital\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" }, "url": { "raw": "{{BASE_URL}}/engine/schema", @@ -13415,7 +13415,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Vital Monitoring 15-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient monitor body vitals for 15 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{VITAL_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract vital data\",\r\n \"Description\": \"Extract vital data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract vital data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Vital\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"Any\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting vital data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:Vital\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Vital Monitoring 15-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient monitor body vitals for 15 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{VITAL_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract vital data\",\r\n \"Description\": \"Extract vital data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract vital data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Vital\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"All\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting vital data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:Vital\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" }, "url": { "raw": "{{BASE_URL}}/engine/schema", @@ -14437,7 +14437,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Vital Monitoring 30-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient monitor body vitals for 30 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{VITAL_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract vital data\",\r\n \"Description\": \"Extract vital data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract vital data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Vital\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"Any\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting vital data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:Vital\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Vital Monitoring 30-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient monitor body vitals for 30 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{VITAL_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract vital data\",\r\n \"Description\": \"Extract vital data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract vital data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"Vital\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"All\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting vital data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:Vital\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" }, "url": { "raw": "{{BASE_URL}}/engine/schema", @@ -15233,178 +15233,6 @@ ] } ] - } - ] - } - ] - }, - { - "name": "Get context for participant / reference id", - "item": [ - { - "name": "Get schema instance by id", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "try {\r", - " var jsonRes = pm.response.json();\r", - " pm.environment.set(\"SCHEMA_INSTANCE_ID\", jsonRes.Data.id);\r", - "}\r", - "catch (error) {\r", - " console.log(error.message);\r", - "}\r", - "\r", - "pm.test(\"Request is successfull\", function () {\r", - " pm.response.to.have.status(200);\r", - " var jsonRes = pm.response.json();\r", - " pm.expect(jsonRes.Status).to.eql('success');\r", - "});\r", - "\r", - "pm.test(\"Schema instance is returned\", function () {\r", - " var jsonRes = pm.response.json();\r", - " pm.expect(jsonRes.Data).to.have.property('id');\r", - " pm.expect(jsonRes.Data).to.have.property('Client');\r", - " pm.expect(jsonRes.Data.Client).to.have.property('id');\r", - " pm.expect(jsonRes.Data).to.have.property('Name');\r", - " pm.expect(jsonRes.Data).to.have.property('Description');\r", - " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", - " pm.expect(jsonRes.Data).to.have.property('RootNodeId');\r", - "});\r", - "" - ], - "type": "text/javascript" - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "" - ], - "type": "text/javascript" - } - } - ], - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [ - { - "key": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "x-api-key", - "value": "{{API_KEY}}", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "{\r\n \"SchemaId\": \"{{SCHEMA_ID}}\",\r\n \"Name\": \"Medication 7 Day Badge Rule\",\r\n \"Description\": \"This rule represents logical steps involved in awarding a badge for consecutive 7 days.\",\r\n \"ParentNodeId\": \"{{SCHEMA_ROOT_NODE_ID}}\",\r\n \"Action\": {\r\n \"ActionType\": \"{{AWARD_BADGE_EVENT_TYPE}}\",\r\n \"Name\": \"Medication 7-Days Badge\",\r\n \"Description\": \"This rule represents logical steps involved in awarding a badge for consecutive 7 days.\",\r\n \"Params\": {\r\n \"Message\": \"Award medication 7-days badge.\",\r\n \"Action\": \"{{AWARD_BADGE_EVENT_TYPE}}\",\r\n \"NextNodeId\": null,\r\n \"Extra\": {}\r\n }\r\n }\r\n}" - }, - "url": { - "raw": "{{BASE_URL}}/engine/schema-instances/{{SCHEMA_INSTANCE_ID}}", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "engine", - "schema-instances", - "{{SCHEMA_INSTANCE_ID}}" - ] - }, - "description": "User login with username/phone/email and password.\n\n'LoginRoleId' is the role id through which user wants to log into the system provided the user has the role." - }, - "response": [] - } - ] - }, - { - "name": "Get participant badges", - "item": [ - { - "name": "Get participant by reference id", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "try {\r", - " var jsonRes = pm.response.json();\r", - " pm.environment.set(\"PARTICIPANT_ID\", jsonRes.Data.id);\r", - "}\r", - "catch (error) {\r", - " console.log(error.message);\r", - "}\r", - "\r", - "pm.test(\"Request is successfull\", function () {\r", - " pm.response.to.have.status(200);\r", - " var jsonRes = pm.response.json();\r", - " pm.expect(jsonRes.Status).to.eql('success');\r", - "});\r", - "\r", - "pm.test(\"Schema instance is returned\", function () {\r", - " var jsonRes = pm.response.json();\r", - " pm.expect(jsonRes.Data).to.have.property('id');\r", - " pm.expect(jsonRes.Data).to.have.property('Client');\r", - " pm.expect(jsonRes.Data.Client).to.have.property('id');\r", - " pm.expect(jsonRes.Data).to.have.property('Name');\r", - " pm.expect(jsonRes.Data).to.have.property('Description');\r", - " pm.expect(jsonRes.Data).to.have.property('ValidFrom');\r", - " pm.expect(jsonRes.Data).to.have.property('RootNodeId');\r", - "});\r", - "" - ], - "type": "text/javascript" - } - }, - { - "listen": "prerequest", - "script": { - "exec": [ - "" - ], - "type": "text/javascript" - } - } - ], - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [ - { - "key": "Content-Type", - "value": "application/json", - "type": "text" - }, - { - "key": "x-api-key", - "value": "{{API_KEY}}", - "type": "text" - } - ], - "body": { - "mode": "raw", - "raw": "" - }, - "url": { - "raw": "{{BASE_URL}}/participants/by-reference-id/{{REFERENCE_ID}}", - "host": [ - "{{BASE_URL}}" - ], - "path": [ - "participants", - "by-reference-id", - "{{REFERENCE_ID}}" - ] }, { "name": "mental health badges", @@ -15785,7 +15613,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Nutrition 7-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient takes chooses mental health monitoring for 7 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{MENTAL_HEALTH_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract mental health data\",\r\n \"Description\": \"Extract mental health data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract mental health data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"MentalHealth\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"Any\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting mental health data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:MentalHealth\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Mental health 7-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient takes chooses mental health monitoring for 7 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{MENTAL_HEALTH_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract mental health data\",\r\n \"Description\": \"Extract mental health data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract mental health data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"MentalHealth\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"Any\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting mental health data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:MentalHealth\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" }, "url": { "raw": "{{BASE_URL}}/engine/schema", @@ -16807,7 +16635,7 @@ ], "body": { "mode": "raw", - "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Mental health 15-Day Badgee\",\r\n \"Description\": \"This schema represents a badge award logic when a patient takes chooses mental health monitoring for 15 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{MENTAL_HEALTH_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract mental health data\",\r\n \"Description\": \"Extract mental health data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract mental health data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"MentalHealth\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"Any\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting mental health data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:MentalHealth\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" + "raw": "{\r\n \"ClientId\": \"{{CLIENT_ID}}\",\r\n \"Name\": \"Mental health 15-Day Badge\",\r\n \"Description\": \"This schema represents a badge award logic when a patient takes chooses mental health monitoring for 15 consecutive days. The patient can keep accumulating these badges.\",\r\n \"Type\": \"Reuse-Existing-Instance\",\r\n \"EventTypeIds\": [\r\n \"{{MENTAL_HEALTH_EVENT_TYPE_ID}}\"\r\n ],\r\n \"RootNode\": {\r\n \"Type\": \"Execution-Node\",\r\n \"Name\": \"Extract mental health data\",\r\n \"Description\": \"Extract mental health data\",\r\n \"Action\": {\r\n \"ActionType\": \"Extract-Data\",\r\n \"Name\": \"Extract mental health data\",\r\n \"InputParams\": {\r\n \"RecordType\": \"MentalHealth\",\r\n \"SourceType\": \"Database\",\r\n \"Filters\": [\r\n {\r\n \"Key\": \"SamplingMethod\",\r\n \"Value\": \"Any\"\r\n }\r\n ]\r\n },\r\n \"OutputParams\": {\r\n \"Message\": \"Extracting mental health data for the given context.\",\r\n \"OutputTag\": \"Extract-Data:MentalHealth\",\r\n \"DestinationType\": \"Almanac\"\r\n }\r\n }\r\n }\r\n}" }, "url": { "raw": "{{BASE_URL}}/engine/schema", From cbf6676fc06b8219ffc3f297c727c2853c81cace Mon Sep 17 00:00:00 2001 From: tabbasum-rean Date: Mon, 19 Jun 2023 13:06:53 +0530 Subject: [PATCH 41/66] WIP - get how to earn badge content API --- .../how.to.earn.badge.content.seed..json | 64 +++++++++++++++++++ src/api/awards/badge/badge.controller.ts | 11 ++++ src/api/awards/badge/badge.routes.ts | 1 + src/database/mappers/awards/badge.mapper.ts | 18 ++++++ src/database/models/awards/badge.model.ts | 3 + src/database/models/user/privilege.model.ts | 2 +- src/database/services/awards/badge.service.ts | 37 ++++++++++- src/domain.types/awards/badge.domain.types.ts | 40 ++++++++---- src/startup/seeder.ts | 37 +++++++++++ 9 files changed, 197 insertions(+), 16 deletions(-) create mode 100644 seed.data/how.to.earn.badge.content.seed..json diff --git a/seed.data/how.to.earn.badge.content.seed..json b/seed.data/how.to.earn.badge.content.seed..json new file mode 100644 index 0000000..fb66a89 --- /dev/null +++ b/seed.data/how.to.earn.badge.content.seed..json @@ -0,0 +1,64 @@ +[ + { + "Name": "7-Day Medication Adherence", + "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + + }, + { + "Name": "15-Day Medication Adherence", + "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + }, + { + "Name": "30-Day Medication Adherence", + "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + }, + { + "Name": "7-Day Healthy Nutrition Choice", + "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + }, + { + "Name": "15-Day Healthy Nutrition Choice", + "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + }, + { + "Name": "30-Day Healthy Nutrition Choice", + "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + }, + { + "Name": "7-Day Physical Activity", + "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + }, + { + "Name": "15-Day Physical Activity", + "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + + }, + { + "Name": "30-Day Physical Activity", + "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + }, + { + "Name": "Mental health 7-Day Badge", + "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + }, + { + "Name": "Mental health 15-Day Badge", + "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + }, + { + "Name": "Mental health 30-Day Badge", + "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + }, + { + "Name": "7-Day Vitals", + "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + }, + { + "Name": "15-Day Vitals", + "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + }, + { + "Name": "30-Day Vitals", + "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + } +] diff --git a/src/api/awards/badge/badge.controller.ts b/src/api/awards/badge/badge.controller.ts index 4ef5a69..33df956 100644 --- a/src/api/awards/badge/badge.controller.ts +++ b/src/api/awards/badge/badge.controller.ts @@ -53,6 +53,17 @@ export class BadgeController extends BaseController { } }; + getAll = async (request: express.Request, response: express.Response) => { + try { + await this.authorize('Badge.GetAll', request, response, false); + const records = await this._service.getAll(); + const message = 'Badge records with how to earn content retrieved successfully!'; + ResponseHandler.success(request, response, message, 200, records); + } catch (error) { + ResponseHandler.handleError(request, response, error); + } + }; + update = async (request: express.Request, response: express.Response) => { try { await this.authorize('Badge.Update', request, response); diff --git a/src/api/awards/badge/badge.routes.ts b/src/api/awards/badge/badge.routes.ts index a112516..4d61786 100644 --- a/src/api/awards/badge/badge.routes.ts +++ b/src/api/awards/badge/badge.routes.ts @@ -15,6 +15,7 @@ export const register = (app: express.Application): void => { const controller = new BadgeController(); router.post('/', authenticator.authenticateClient, authenticator.authenticateUser, controller.create); + router.get('/how-to-earn', authenticator.authenticateClient, controller.getAll); router.get('/stock-images', authenticator.authenticateClient, controller.getStockBadgeImages); router.get('/search', authenticator.authenticateClient, authenticator.authenticateUser, controller.search); router.get('/:id', authenticator.authenticateClient, authenticator.authenticateUser, controller.getById); diff --git a/src/database/mappers/awards/badge.mapper.ts b/src/database/mappers/awards/badge.mapper.ts index 2ba2d76..132bd78 100644 --- a/src/database/mappers/awards/badge.mapper.ts +++ b/src/database/mappers/awards/badge.mapper.ts @@ -1,5 +1,6 @@ import { Badge } from '../../models/awards/badge.model'; import { + BadgeDto, BadgeResponseDto } from '../../../domain.types/awards/badge.domain.types'; @@ -26,6 +27,23 @@ export class BadgeMapper { Name : badge.Name, Description: badge.Description, ImageUrl : badge.ImageUrl, + HowToEarn : badge.HowToEarn, + CreatedAt : badge.CreatedAt, + UpdatedAt : badge.UpdatedAt, + }; + return dto; + }; + + static toDto = (badge: Badge): BadgeDto => { + if (badge == null) { + return null; + } + const dto: BadgeDto = { + id : badge.id, + Name : badge.Name, + Description: badge.Description, + ImageUrl : badge.ImageUrl, + HowToEarn : badge.HowToEarn, CreatedAt : badge.CreatedAt, UpdatedAt : badge.UpdatedAt, }; diff --git a/src/database/models/awards/badge.model.ts b/src/database/models/awards/badge.model.ts index 9a2b025..44f733b 100644 --- a/src/database/models/awards/badge.model.ts +++ b/src/database/models/awards/badge.model.ts @@ -40,6 +40,9 @@ export class Badge { @JoinTable() Category: BadgeCategory; + @Column({ type: 'varchar', length: 4096, nullable: true }) + HowToEarn : string; + @CreateDateColumn() CreatedAt : Date; diff --git a/src/database/models/user/privilege.model.ts b/src/database/models/user/privilege.model.ts index fec4f64..ce04556 100644 --- a/src/database/models/user/privilege.model.ts +++ b/src/database/models/user/privilege.model.ts @@ -18,7 +18,7 @@ export class Privilege { @PrimaryGeneratedColumn('uuid') id : string; - @Column({ type: 'varchar', length: 32, nullable: false, unique: true }) + @Column({ type: 'varchar', length: 128, nullable: false, unique: true }) Name : string; @Column({ type: 'varchar', length: 1024, nullable: true }) diff --git a/src/database/services/awards/badge.service.ts b/src/database/services/awards/badge.service.ts index 1742111..c1735e9 100644 --- a/src/database/services/awards/badge.service.ts +++ b/src/database/services/awards/badge.service.ts @@ -10,6 +10,7 @@ import { BaseService } from '../base.service'; import { uuid } from '../../../domain.types/miscellaneous/system.types'; import { BadgeCreateModel, + BadgeDto, BadgeResponseDto, BadgeSearchFilters, BadgeSearchResults, @@ -63,6 +64,16 @@ export class BadgeService extends BaseService { } }; + public getAll = async (): Promise => { + try { + var badges = await this._badgeRepository.find(); + return badges.map(x => BadgeMapper.toDto(x)); + } catch (error) { + logger.error(error.message); + ErrorHandler.throwInternalServerError(error.message, 500); + } + }; + public getByClientId = async (clientId: uuid): Promise => { try { var badges = await this._badgeRepository.find({ @@ -89,6 +100,7 @@ export class BadgeService extends BaseService { var search = this.getSearchModel(filters); var { search, pageIndex, limit, order, orderByColumn } = this.addSortingAndPagination(search, filters); const [list, count] = await this._badgeRepository.findAndCount(search); + const searchResults = { TotalCount : count, RetrievedCount : list.length, @@ -96,7 +108,7 @@ export class BadgeService extends BaseService { ItemsPerPage : limit, Order : order === 'DESC' ? 'descending' : 'ascending', OrderedBy : orderByColumn, - Items : list.map(x => BadgeMapper.toResponseDto(x)), + Items : list.map(x => BadgeMapper.toDto(x)), }; return searchResults; } catch (error) { @@ -144,6 +156,29 @@ export class BadgeService extends BaseService { } }; + public updateContent = async (id: uuid, model: BadgeUpdateModel) + : Promise => { + try { + const badge = await this._badgeRepository.findOne({ + where : { + id : id + } + }); + if (!badge) { + ErrorHandler.throwNotFoundError('Badge not found!'); + } + + if (model.HowToEarn != null) { + badge.HowToEarn = model.HowToEarn; + } + var record = await this._badgeRepository.save(badge); + return BadgeMapper.toDto(record); + } catch (error) { + logger.error(error.message); + ErrorHandler.throwInternalServerError(error.message, 500); + } + }; + public delete = async (id: string): Promise => { try { var record = await this._badgeRepository.findOne({ diff --git a/src/domain.types/awards/badge.domain.types.ts b/src/domain.types/awards/badge.domain.types.ts index 6bd5e4d..fe83614 100644 --- a/src/domain.types/awards/badge.domain.types.ts +++ b/src/domain.types/awards/badge.domain.types.ts @@ -22,25 +22,37 @@ export interface BadgeUpdateModel { Name? : string; Description? : string; ImageUrl? : string; + HowToEarn? : string; } export interface BadgeResponseDto { - id : uuid; - Name : string; - Description: string; - ImageUrl : string; - Category : { - id : uuid; - Name : string; - Description: string; + id : uuid; + Name : string; + Description : string; + ImageUrl : string; + HowToEarn : string; + Category : { + id : uuid; + Name : string; + Description : string; }; Client: { - id : uuid; - Name: string; - Code: string; + id : uuid; + Name : string; + Code : string; }; - CreatedAt: Date; - UpdatedAt: Date; + CreatedAt : Date; + UpdatedAt : Date; +} + +export interface BadgeDto { + id : uuid; + Name : string; + Description : string; + ImageUrl : string; + HowToEarn : string; + CreatedAt : Date; + UpdatedAt : Date; } export interface BadgeSearchFilters extends BaseSearchFilters { @@ -50,5 +62,5 @@ export interface BadgeSearchFilters extends BaseSearchFilters { } export interface BadgeSearchResults extends BaseSearchResults { - Items: BadgeResponseDto[]; + Items: BadgeDto[]; } diff --git a/src/startup/seeder.ts b/src/startup/seeder.ts index 87f5d54..c042921 100644 --- a/src/startup/seeder.ts +++ b/src/startup/seeder.ts @@ -2,6 +2,7 @@ import fs from "fs"; import path from "path"; import { logger } from "../logger/logger"; import * as RolePrivilegesList from '../../seed.data/role.privileges.json'; +import * as seedHowToEarnBadgeContent from '../../seed.data/how.to.earn.badge.content.seed..json'; import { UserService } from '../database/services/user/user.service'; import { UserCreateModel } from "../domain.types/user/user.domain.types"; import { Gender } from "../domain.types/miscellaneous/system.types"; @@ -16,6 +17,8 @@ import { BadgeStockImageDomainModel } from "../domain.types/badge.stock.image/ba import { BadgeStockImageService } from "../database/services/badge.stock.images/badge.stock.image.service"; import { ClientService } from "../database/services/client/client.service"; import { Loader } from "./loader"; +import { BadgeService } from "../database/services/awards/badge.service"; +import { BadgeUpdateModel } from "../domain.types/awards/badge.domain.types"; ////////////////////////////////////////////////////////////////////////////// @@ -33,6 +36,8 @@ export class Seeder { _badgeStockImageService: BadgeStockImageService = new BadgeStockImageService(); + _badgeService: BadgeService = new BadgeService(); + constructor () { this._fileResourceService = Loader.Container.resolve(FileResourceService); @@ -48,6 +53,7 @@ export class Seeder { await this.seedRolePrivileges(); await this.seedDefaultUsers(clients); await this.seedBadgeStockImages(); + await this.seedHowToEarnBadgeContent(); } catch (error) { logger.error(error.message); } @@ -237,4 +243,35 @@ export class Seeder { } }; + public seedHowToEarnBadgeContent = async () => { + + logger.info('Seeding how to earn content for badges...'); + + const arr = seedHowToEarnBadgeContent['default']; + //console.log(JSON.stringify(arr, null, 2)); + + for (let i = 0; i < arr.length; i++) { + + const filters = { + Name : arr[i]['Name'] + }; + + const existingRecord = await this._badgeService.search(filters); + //console.log(JSON.stringify(existingRecord, null, 2)); + + if (existingRecord.Items.length > 0) { + + const entity = existingRecord.Items[0]; + const model: BadgeUpdateModel = { + HowToEarn : arr[i]['HowToEarn'] + }; + + var record = await this._badgeService.updateContent(entity.id, model); + var str = JSON.stringify(record, null, ' '); + logger.info(str); + } + + } + }; + } From 9d14d14e4088792731cd83632c3929770a9073a7 Mon Sep 17 00:00:00 2001 From: Vaibhav Dalal Date: Tue, 20 Jun 2023 19:31:31 +0530 Subject: [PATCH 42/66] Added pr-ci-cd workflow --- .github/workflows/codeql-analysis.yml | 46 ++++++++++++++++ .github/workflows/pr-ci-cd.yml | 76 +++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml create mode 100644 .github/workflows/pr-ci-cd.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..b04a1dc --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,46 @@ + + +name: "CodeQL" + +on: + # Triggers the workflow on push or pull request events but only for the main branch + push: + branches: [main, develop] + pull_request: + branches: [main, develop] + # workflow_dispatch: + +jobs: + analyze-codeql: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: ["typescript"] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] + # Learn more: + # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + config-file: ./.github/codeql/codeql-config.yml + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 \ No newline at end of file diff --git a/.github/workflows/pr-ci-cd.yml b/.github/workflows/pr-ci-cd.yml new file mode 100644 index 0000000..0982f8d --- /dev/null +++ b/.github/workflows/pr-ci-cd.yml @@ -0,0 +1,76 @@ +# This workflow will trigger pull requests and apply a label based on the +# paths that are modified in the pull request. +# +# To use this workflow, you will need to set up a .github/labeler.yml +# file with configuration. For more information, see: +# https://github.com/actions/labeler + +name: PR-CI-CD + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the develop branch + pull_request: + branches: [develop] + +jobs: + CodeScan-ESLint: + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v2.3.4 + with: + fetch-depth: 0 + + - name: Lint Code Base + uses: docker://ghcr.io/github/super-linter:latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + LINTER_RULES_PATH: / + TYPESCRIPT_ES_CONFIG_FILE: .eslintrc.json + VALIDATE_TYPESCRIPT_ES: true + VALIDATE_ALL_CODEBASE: false + DEFAULT_BRANCH: develop + + Build-Docker-Image: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Declare some variables + id: vars + shell: bash + run: | + echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/} | sed "s/\\//-/g")" + echo "::set-output name=sha_short::$(git rev-parse --short HEAD)" + echo "::set-output name=repo_name::$(echo "$GITHUB_REPOSITORY" | awk -F / '{print $2}')" + + - name: Another step + run: | + echo "Branch: ${{ steps.vars.outputs.branch }}" + echo "Sha: ${{ steps.vars.outputs.sha_short }}" + echo "Repo: ${{ steps.vars.outputs.repo_name }}" + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Cache Docker layers + uses: actions/cache@v2 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Build + id: docker_build + uses: docker/build-push-action@v2 + with: + context: ./ + file: ./Dockerfile + builder: ${{ steps.buildx.outputs.name }} + push: false + tags: reancare/services:${{ steps.vars.outputs.branch }}_${{ steps.vars.outputs.sha_short }} + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache \ No newline at end of file From 6c3e390f3e0d497f5ac7984631430886306117ab Mon Sep 17 00:00:00 2001 From: Vaibhav Dalal Date: Tue, 20 Jun 2023 19:36:31 +0530 Subject: [PATCH 43/66] Added pr-ci-cd workflow --- .github/{workflows => codeql}/codeql-analysis.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{workflows => codeql}/codeql-analysis.yml (100%) diff --git a/.github/workflows/codeql-analysis.yml b/.github/codeql/codeql-analysis.yml similarity index 100% rename from .github/workflows/codeql-analysis.yml rename to .github/codeql/codeql-analysis.yml From a185b385f37f2ab509a957706070145d68147bc0 Mon Sep 17 00:00:00 2001 From: vinay-debug <84920398+vinay-debug@users.noreply.github.com> Date: Wed, 21 Jun 2023 01:38:53 +0530 Subject: [PATCH 44/66] Fixed number of batches issue --- .../processor/providers/implementation/data.comparator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/processor/providers/implementation/data.comparator.ts b/src/modules/processor/providers/implementation/data.comparator.ts index d856073..2926ac4 100644 --- a/src/modules/processor/providers/implementation/data.comparator.ts +++ b/src/modules/processor/providers/implementation/data.comparator.ts @@ -42,7 +42,7 @@ export class DataComparator implements IDataComparator { if (toBeAdded.length > 0) { for (const r of referenceRange) { const found = toBeAdded.find(x => x.key === r.key); - if (!found) { + if (found) { toBeRemoved.push(r); } } From b0bf6240f369405b4000c2670d2127e3dbc2182e Mon Sep 17 00:00:00 2001 From: vinay-debug <84920398+vinay-debug@users.noreply.github.com> Date: Wed, 21 Jun 2023 01:40:18 +0530 Subject: [PATCH 45/66] Fixed linting issue --- .../engine.execution/execution.types.ts | 19 ++++++++-- src/modules/engine.execution/schema.engine.ts | 36 +++++++++---------- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/modules/engine.execution/execution.types.ts b/src/modules/engine.execution/execution.types.ts index d1a751d..4ba5ba1 100644 --- a/src/modules/engine.execution/execution.types.ts +++ b/src/modules/engine.execution/execution.types.ts @@ -59,29 +59,43 @@ export class CCondition { } export class CContext { + id : uuid; + ReferenceId : uuid; + Type : ContextType; + Participant?: { id : uuid; FirstName: string; LastName : string; }; + ParticipantGroup ?: { id : uuid; Name : string; Description: string; - } + }; + } export class CAction { + id : uuid; + ActionType : EventActionType; + Name : string | undefined; + Description : string | undefined; + ParentNodeId: uuid | undefined; + InputParams : any; + OutputParams: ActionOutputParams; + } export class CNode { @@ -249,6 +263,7 @@ export class CSchemaInstance { Almanac : AlmanacObject[]; CSchemaInstance() { + // } public setCurrent = (instance: CNodeInstance) => { @@ -257,6 +272,6 @@ export class CSchemaInstance { public fetchAlmanacData = (tag: string) => { return this.Almanac.find(x => x.Name === tag); - } + }; } diff --git a/src/modules/engine.execution/schema.engine.ts b/src/modules/engine.execution/schema.engine.ts index 83333b9..3ca68db 100644 --- a/src/modules/engine.execution/schema.engine.ts +++ b/src/modules/engine.execution/schema.engine.ts @@ -30,7 +30,7 @@ export class SchemaEngine { logger.info(`Current node : ${currentNodeInstance.Name}`); logger.info(`Current node Id : ${currentNodeInstance.id}`); - while (currentNodeInstance && + while (currentNodeInstance && currentNodeInstance.ExecutionStatus === ExecutionStatus.Pending) { currentNodeInstance = await SchemaEngine.traverse( schemaInstance.Context, @@ -47,7 +47,7 @@ export class SchemaEngine { schemaInstance: CSchemaInstance, currentNodeInstance: CNodeInstance, facts: any - ): Promise { + ): Promise { const processor = Loader.Container.resolve(ProcessorService); @@ -80,8 +80,8 @@ export class SchemaEngine { //Extract data based on the action subject filters const data = await processor.extractData(context.id, action.InputParams, action.OutputParams); schemaInstance.Almanac.push({ - Name: data.Tag, - Data: data.Data + Name : data.Tag, + Data : data.Data }); return SchemaEngine.getNextNode(currentNodeInstance, schemaInstance); } @@ -94,12 +94,12 @@ export class SchemaEngine { } if (dataActionType === DataActionType.CalculateContinuity) { const data = await processor.calculateContinuity( - almanacObject.Data, - action.InputParams as ContinuityInputParams, + almanacObject.Data, + action.InputParams as ContinuityInputParams, action.OutputParams as OutputParams); schemaInstance.Almanac.push({ - Name: data.Tag, - Data: data.Data + Name : data.Tag, + Data : data.Data }); } @@ -118,13 +118,13 @@ export class SchemaEngine { } if (dataActionType === DataActionType.FindRangeDifference) { const data = await processor.compareRanges( - almanacObjectFirst.Data, + almanacObjectFirst.Data, almanacObjectSecond.Data, - action.InputParams as RangeComparisonInputParams, + action.InputParams as RangeComparisonInputParams, action.OutputParams as OutputParams); schemaInstance.Almanac.push({ - Name: data.Tag, - Data: data.Data + Name : data.Tag, + Data : data.Data }); } @@ -144,10 +144,10 @@ export class SchemaEngine { } schemaInstance.Almanac.push({ - Name: action.OutputParams.OutputTag, - Data: { - Added : added.Data, - Removed: removedData, + Name : action.OutputParams.OutputTag, + Data : { + Added : added.Data, + Removed : removedData, } }); return SchemaEngine.getNextNode(currentNodeInstance, schemaInstance); @@ -212,8 +212,8 @@ export class SchemaEngine { } private static getNextNode = (currentNodeInstance, schemaInstance) => { - if (currentNodeInstance.Action && - currentNodeInstance.Action.OutputParams && + if (currentNodeInstance.Action && + currentNodeInstance.Action.OutputParams && currentNodeInstance.Action.OutputParams.NextNodeId) { const nextNodeId = currentNodeInstance.Action.OutputParams.NextNodeId; const nodeInstances = schemaInstance.NodeInstances; From 33d7642f58f316c7dbc707bfd424761b6a17c466 Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 21 Jun 2023 15:00:32 +0530 Subject: [PATCH 46/66] Create prod.yml --- .github/workflows/prod.yml | 109 +++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 .github/workflows/prod.yml diff --git a/.github/workflows/prod.yml b/.github/workflows/prod.yml new file mode 100644 index 0000000..6d43ddf --- /dev/null +++ b/.github/workflows/prod.yml @@ -0,0 +1,109 @@ +name: PROD-CI-CD + +# Controls when the workflow will run +on: + # Triggers the workflow on push events but only for the develop branch + push: + branches: [main] + +jobs: + + Publish-Release: + runs-on: ubuntu-latest + steps: + - name: New Release Publish + id: new_publish + uses: release-drafter/release-drafter@v5 + with: + publish : true + env: + GITHUB_TOKEN: ${{ secrets.PAT_GITHUB }} + + outputs: + release_id: ${{ steps.new_publish.outputs.id }} + release_name: ${{ steps.new_publish.outputs.tag_name }} + + + Deploy-ECS: + needs: Publish-Release + environment: prod + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to Amazon ECR + id: login-ecr + run: | + aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws + + - name: Cache Docker layers + uses: actions/cache@v3 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Build and push + id: docker_build + uses: docker/build-push-action@v3 + with: + context: ./ + file: ./Dockerfile + builder: ${{ steps.buildx.outputs.name }} + push: true + tags: ${{ steps.login-ecr.outputs.registry }}/awards-service:${{ needs.Publish-Release.outputs.release_name }}_${{ needs.Publish-Release.outputs.release_id }} + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache + + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} + + - name: Download task definition + run: | + aws ecs describe-task-definition --task-definition ${{ secrets.TASK_DEFINTION_NAME }} \ + --query taskDefinition > task-definition.json + + - name: New image ID in the Amazon ECS task definition + id: task-def + uses: aws-actions/amazon-ecs-render-task-definition@v1 + with: + task-definition: task-definition.json + container-name: default + image: ${{ steps.login-ecr.outputs.registry }}/awards-service:${{ needs.Publish-Release.outputs.release_name }}_${{ needs.Publish-Release.outputs.release_id }} + + - name: Deploy Amazon ECS task definition + uses: aws-actions/amazon-ecs-deploy-task-definition@v1 + with: + task-definition: ${{ steps.task-def.outputs.task-definition }} + wait-for-service-stability: true + + - name: Task Definition Variable + id: taskdefintionvar + shell: bash + run: | + echo "task_definition_arn=$(aws ecs describe-task-definition --task-definition ${{ secrets.TASK_DEFINTION_NAME }} | jq '.[] | .taskDefinitionArn')" >> $GITHUB_OUTPUT + + - name: Task Defintion ARN + run: | + echo "Task Defintion: ${{ steps.taskdefintionvar.outputs.task_definition_arn }}" + + - name: Deploy Amazon ECS task definition using Duplo API + uses: fjogeleit/http-request-action@master + with: + url: 'https://reanfoundation.duplocloud.net/subscriptions/${{ secrets.DUPLO_ID }}/UpdateEcsService' + method: 'POST' + data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "${{ secrets.SERVICE_NAME }}","Replicas":1, "HealthCheckGracePeriodSeconds": 1200}' + bearerToken: ${{ secrets.DUPLOCLOUD_TOKEN }} From 1b06ead972651465cf8224786f4a41ed7d94fd10 Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 21 Jun 2023 15:09:10 +0530 Subject: [PATCH 47/66] Update prod.yml --- .github/workflows/prod.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/prod.yml b/.github/workflows/prod.yml index 6d43ddf..9a31ea6 100644 --- a/.github/workflows/prod.yml +++ b/.github/workflows/prod.yml @@ -4,7 +4,7 @@ name: PROD-CI-CD on: # Triggers the workflow on push events but only for the develop branch push: - branches: [main] + branches: [develop] jobs: From 5df6077399b801f894da0d8620c101028e7186a1 Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 21 Jun 2023 15:10:27 +0530 Subject: [PATCH 48/66] Create release-drafter.yml --- .github/release-drafter.yml | 51 +++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .github/release-drafter.yml diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 0000000..78cb6a8 --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,51 @@ +change-template: "* $TITLE (#$NUMBER) by @$AUTHOR" +name-template: '$RESOLVED_VERSION' +tag-template: 'v$RESOLVED_VERSION' +categories: + - title: '⚑ Breaking Changes' + labels: + - 'breaking-change' + - title: '🌟New features and non-breaking changes' + labels: + - 'major' + - 'feature' + - title: '🌟 Minor Changes' + labels: + - 'enhancement' + - title: 'πŸ“œ Documentation updates' + labels: + - 'documentation' + - title: 'πŸ› Bug and hot fixes' + labels: + - 'bug' + - 'fix' + - title: 'πŸš’ Deprecations' + labels: + - 'deprecated' + - title: 'πŸ”§ Maintenance' + labels: + - 'internal' + - 'dependencies' +exclude-labels: + - 'skip-changelog' +version-resolver: + major: + labels: + - 'major' + minor: + labels: + - 'minor' + patch: + labels: + - 'patch' + default: major +template: | + ## Summary + + ## Changes + + $CHANGES + + ## This release was made possible by the following contributors: + + $CONTRIBUTORS From 166a4f468601b76b094055db85b54c534baa612f Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 21 Jun 2023 15:12:01 +0530 Subject: [PATCH 49/66] Update prod.yml --- .github/workflows/prod.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/prod.yml b/.github/workflows/prod.yml index 9a31ea6..6d43ddf 100644 --- a/.github/workflows/prod.yml +++ b/.github/workflows/prod.yml @@ -4,7 +4,7 @@ name: PROD-CI-CD on: # Triggers the workflow on push events but only for the develop branch push: - branches: [develop] + branches: [main] jobs: From c6c107786acaf5928011a8d17bfab0297eebe849 Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 21 Jun 2023 15:13:30 +0530 Subject: [PATCH 50/66] Update prod.yml --- .github/workflows/prod.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/prod.yml b/.github/workflows/prod.yml index 6d43ddf..9a31ea6 100644 --- a/.github/workflows/prod.yml +++ b/.github/workflows/prod.yml @@ -4,7 +4,7 @@ name: PROD-CI-CD on: # Triggers the workflow on push events but only for the develop branch push: - branches: [main] + branches: [develop] jobs: From 93d1fffb6a8256621e50c1f6d9c39254edfe794d Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 21 Jun 2023 15:25:46 +0530 Subject: [PATCH 51/66] Update prod.yml --- .github/workflows/prod.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/prod.yml b/.github/workflows/prod.yml index 9a31ea6..9cfa379 100644 --- a/.github/workflows/prod.yml +++ b/.github/workflows/prod.yml @@ -64,7 +64,7 @@ jobs: file: ./Dockerfile builder: ${{ steps.buildx.outputs.name }} push: true - tags: ${{ steps.login-ecr.outputs.registry }}/awards-service:${{ needs.Publish-Release.outputs.release_name }}_${{ needs.Publish-Release.outputs.release_id }} + tags: public.ecr.aws/i9y2d4u3/awards-service:${{ needs.Publish-Release.outputs.release_name }}_${{ needs.Publish-Release.outputs.release_id }} cache-from: type=local,src=/tmp/.buildx-cache cache-to: type=local,dest=/tmp/.buildx-cache @@ -82,7 +82,7 @@ jobs: with: task-definition: task-definition.json container-name: default - image: ${{ steps.login-ecr.outputs.registry }}/awards-service:${{ needs.Publish-Release.outputs.release_name }}_${{ needs.Publish-Release.outputs.release_id }} + image: public.ecr.aws/i9y2d4u3/awards-service:${{ needs.Publish-Release.outputs.release_name }}_${{ needs.Publish-Release.outputs.release_id }} - name: Deploy Amazon ECS task definition uses: aws-actions/amazon-ecs-deploy-task-definition@v1 From 53259d803f33eb4721c8c08ad92a049eab32f571 Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 21 Jun 2023 15:31:37 +0530 Subject: [PATCH 52/66] Update prod.yml --- .github/workflows/prod.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/prod.yml b/.github/workflows/prod.yml index 9cfa379..9ebd798 100644 --- a/.github/workflows/prod.yml +++ b/.github/workflows/prod.yml @@ -5,6 +5,9 @@ on: # Triggers the workflow on push events but only for the develop branch push: branches: [develop] + +permissions: + contents: write jobs: @@ -17,7 +20,7 @@ jobs: with: publish : true env: - GITHUB_TOKEN: ${{ secrets.PAT_GITHUB }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} outputs: release_id: ${{ steps.new_publish.outputs.id }} From f5791437af70d86e4b26980f274bfc6dbd952bb4 Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 21 Jun 2023 16:33:01 +0530 Subject: [PATCH 53/66] Update prod.yml --- .github/workflows/prod.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/prod.yml b/.github/workflows/prod.yml index 9ebd798..2384314 100644 --- a/.github/workflows/prod.yml +++ b/.github/workflows/prod.yml @@ -9,6 +9,7 @@ on: permissions: contents: write + jobs: Publish-Release: From 1c26d3b7bd2be500c51f32e94a2ee9f51d384b65 Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 21 Jun 2023 17:04:22 +0530 Subject: [PATCH 54/66] Update prod.yml --- .github/workflows/prod.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/prod.yml b/.github/workflows/prod.yml index 2384314..9ebd798 100644 --- a/.github/workflows/prod.yml +++ b/.github/workflows/prod.yml @@ -9,7 +9,6 @@ on: permissions: contents: write - jobs: Publish-Release: From 9a31b6b7ef360af98533a213f354848d564e2b7d Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 21 Jun 2023 18:05:10 +0530 Subject: [PATCH 55/66] Update prod.yml --- .github/workflows/prod.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/prod.yml b/.github/workflows/prod.yml index 9ebd798..b254a4a 100644 --- a/.github/workflows/prod.yml +++ b/.github/workflows/prod.yml @@ -108,5 +108,5 @@ jobs: with: url: 'https://reanfoundation.duplocloud.net/subscriptions/${{ secrets.DUPLO_ID }}/UpdateEcsService' method: 'POST' - data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "${{ secrets.SERVICE_NAME }}","Replicas":1, "HealthCheckGracePeriodSeconds": 1200}' + data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "${{ secrets.SERVICE_NAME }}","Replicas":1, "HealthCheckGracePeriodSeconds": 1200, "DnsPrfx": ""}' bearerToken: ${{ secrets.DUPLOCLOUD_TOKEN }} From 00a79d1804e0562db2a6aed9c7dbe922c5266f00 Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Wed, 21 Jun 2023 19:34:21 +0530 Subject: [PATCH 56/66] Update prod.yml --- .github/workflows/prod.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/prod.yml b/.github/workflows/prod.yml index b254a4a..01cb422 100644 --- a/.github/workflows/prod.yml +++ b/.github/workflows/prod.yml @@ -4,7 +4,7 @@ name: PROD-CI-CD on: # Triggers the workflow on push events but only for the develop branch push: - branches: [develop] + branches: [main] permissions: contents: write From 9623b013972a9947479473aeed88a8e7830fc7cb Mon Sep 17 00:00:00 2001 From: tabbasum-rean Date: Thu, 22 Jun 2023 12:24:00 +0530 Subject: [PATCH 57/66] Get how to earn badge content API --- src/api/awards/badge/badge.controller.ts | 2 +- src/database/mappers/awards/badge.mapper.ts | 17 -------- src/database/models/user/privilege.model.ts | 2 +- src/database/services/awards/badge.service.ts | 40 +++---------------- src/domain.types/awards/badge.domain.types.ts | 12 +----- src/startup/seeder.ts | 6 ++- 6 files changed, 13 insertions(+), 66 deletions(-) diff --git a/src/api/awards/badge/badge.controller.ts b/src/api/awards/badge/badge.controller.ts index 33df956..96d76f9 100644 --- a/src/api/awards/badge/badge.controller.ts +++ b/src/api/awards/badge/badge.controller.ts @@ -56,7 +56,7 @@ export class BadgeController extends BaseController { getAll = async (request: express.Request, response: express.Response) => { try { await this.authorize('Badge.GetAll', request, response, false); - const records = await this._service.getAll(); + const records = await this._service.search({}); const message = 'Badge records with how to earn content retrieved successfully!'; ResponseHandler.success(request, response, message, 200, records); } catch (error) { diff --git a/src/database/mappers/awards/badge.mapper.ts b/src/database/mappers/awards/badge.mapper.ts index 132bd78..0c0d228 100644 --- a/src/database/mappers/awards/badge.mapper.ts +++ b/src/database/mappers/awards/badge.mapper.ts @@ -1,6 +1,5 @@ import { Badge } from '../../models/awards/badge.model'; import { - BadgeDto, BadgeResponseDto } from '../../../domain.types/awards/badge.domain.types'; @@ -34,20 +33,4 @@ export class BadgeMapper { return dto; }; - static toDto = (badge: Badge): BadgeDto => { - if (badge == null) { - return null; - } - const dto: BadgeDto = { - id : badge.id, - Name : badge.Name, - Description: badge.Description, - ImageUrl : badge.ImageUrl, - HowToEarn : badge.HowToEarn, - CreatedAt : badge.CreatedAt, - UpdatedAt : badge.UpdatedAt, - }; - return dto; - }; - } diff --git a/src/database/models/user/privilege.model.ts b/src/database/models/user/privilege.model.ts index ce04556..fec4f64 100644 --- a/src/database/models/user/privilege.model.ts +++ b/src/database/models/user/privilege.model.ts @@ -18,7 +18,7 @@ export class Privilege { @PrimaryGeneratedColumn('uuid') id : string; - @Column({ type: 'varchar', length: 128, nullable: false, unique: true }) + @Column({ type: 'varchar', length: 32, nullable: false, unique: true }) Name : string; @Column({ type: 'varchar', length: 1024, nullable: true }) diff --git a/src/database/services/awards/badge.service.ts b/src/database/services/awards/badge.service.ts index c1735e9..e853ea2 100644 --- a/src/database/services/awards/badge.service.ts +++ b/src/database/services/awards/badge.service.ts @@ -10,7 +10,6 @@ import { BaseService } from '../base.service'; import { uuid } from '../../../domain.types/miscellaneous/system.types'; import { BadgeCreateModel, - BadgeDto, BadgeResponseDto, BadgeSearchFilters, BadgeSearchResults, @@ -64,16 +63,6 @@ export class BadgeService extends BaseService { } }; - public getAll = async (): Promise => { - try { - var badges = await this._badgeRepository.find(); - return badges.map(x => BadgeMapper.toDto(x)); - } catch (error) { - logger.error(error.message); - ErrorHandler.throwInternalServerError(error.message, 500); - } - }; - public getByClientId = async (clientId: uuid): Promise => { try { var badges = await this._badgeRepository.find({ @@ -108,7 +97,7 @@ export class BadgeService extends BaseService { ItemsPerPage : limit, Order : order === 'DESC' ? 'descending' : 'ascending', OrderedBy : orderByColumn, - Items : list.map(x => BadgeMapper.toDto(x)), + Items : list.map(x => BadgeMapper.toResponseDto(x)), }; return searchResults; } catch (error) { @@ -148,31 +137,11 @@ export class BadgeService extends BaseService { if (model.ImageUrl != null) { badge.ImageUrl = model.ImageUrl; } - var record = await this._badgeRepository.save(badge); - return BadgeMapper.toResponseDto(record); - } catch (error) { - logger.error(error.message); - ErrorHandler.throwInternalServerError(error.message, 500); - } - }; - - public updateContent = async (id: uuid, model: BadgeUpdateModel) - : Promise => { - try { - const badge = await this._badgeRepository.findOne({ - where : { - id : id - } - }); - if (!badge) { - ErrorHandler.throwNotFoundError('Badge not found!'); - } - if (model.HowToEarn != null) { badge.HowToEarn = model.HowToEarn; } var record = await this._badgeRepository.save(badge); - return BadgeMapper.toDto(record); + return BadgeMapper.toResponseDto(record); } catch (error) { logger.error(error.message); ErrorHandler.throwInternalServerError(error.message, 500); @@ -199,7 +168,9 @@ export class BadgeService extends BaseService { private getSearchModel = (filters: BadgeSearchFilters) => { var search : FindManyOptions = { - relations : { + relations: { + Category: true, + Client : true }, where : { }, @@ -218,6 +189,7 @@ export class BadgeService extends BaseService { Name : true, Description: true, ImageUrl : true, + HowToEarn : true, CreatedAt : true, UpdatedAt : true, } diff --git a/src/domain.types/awards/badge.domain.types.ts b/src/domain.types/awards/badge.domain.types.ts index fe83614..dd2fff0 100644 --- a/src/domain.types/awards/badge.domain.types.ts +++ b/src/domain.types/awards/badge.domain.types.ts @@ -45,16 +45,6 @@ export interface BadgeResponseDto { UpdatedAt : Date; } -export interface BadgeDto { - id : uuid; - Name : string; - Description : string; - ImageUrl : string; - HowToEarn : string; - CreatedAt : Date; - UpdatedAt : Date; -} - export interface BadgeSearchFilters extends BaseSearchFilters { Name ? : string; CategoryId ? : uuid; @@ -62,5 +52,5 @@ export interface BadgeSearchFilters extends BaseSearchFilters { } export interface BadgeSearchResults extends BaseSearchResults { - Items: BadgeDto[]; + Items: BadgeResponseDto[]; } diff --git a/src/startup/seeder.ts b/src/startup/seeder.ts index c042921..41d9393 100644 --- a/src/startup/seeder.ts +++ b/src/startup/seeder.ts @@ -263,10 +263,12 @@ export class Seeder { const entity = existingRecord.Items[0]; const model: BadgeUpdateModel = { - HowToEarn : arr[i]['HowToEarn'] + HowToEarn : arr[i]['HowToEarn'], + ClientId : entity.Client.id, + CategoryId : entity.Category.id }; - var record = await this._badgeService.updateContent(entity.id, model); + var record = await this._badgeService.update(entity.id, model); var str = JSON.stringify(record, null, ' '); logger.info(str); } From 778d479cbf559d2e8570520f3496960dfa0c1bbd Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Thu, 22 Jun 2023 14:59:55 +0530 Subject: [PATCH 58/66] Update prod.yml --- .github/workflows/prod.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/prod.yml b/.github/workflows/prod.yml index 01cb422..e0e31db 100644 --- a/.github/workflows/prod.yml +++ b/.github/workflows/prod.yml @@ -4,7 +4,7 @@ name: PROD-CI-CD on: # Triggers the workflow on push events but only for the develop branch push: - branches: [main] + branches: main permissions: contents: write From fd8695622951ff87a3385e9117451228e6b9dcac Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Fri, 23 Jun 2023 12:09:28 +0530 Subject: [PATCH 59/66] Create aha-uat-ci-cd.yml --- .github/workflows/aha-uat-ci-cd.yml | 141 ++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 .github/workflows/aha-uat-ci-cd.yml diff --git a/.github/workflows/aha-uat-ci-cd.yml b/.github/workflows/aha-uat-ci-cd.yml new file mode 100644 index 0000000..11c4235 --- /dev/null +++ b/.github/workflows/aha-uat-ci-cd.yml @@ -0,0 +1,141 @@ +name: AHA-UAT-CI-CD + +# Controls when the workflow will run +on: + # Triggers the workflow on push events but only for the develop branch + workflow_dispatch: + inputs: + Tag_name: + description: Tag name of your release(please include "v") + required: true + +jobs: + + CodeScan-ESLint: + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Lint Code Base + uses: github/super-linter@v4 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + LINTER_RULES_PATH: / + TYPESCRIPT_ES_CONFIG_FILE: .eslintrc.json + VALIDATE_TYPESCRIPT_ES: true + + + Github-ECR-Tag-Check: + runs-on: ubuntu-latest + steps: + - name: check tag + uses: mukunku/tag-exists-action@v1.2.0 + id: checkTag + with: + tag: ${{ github.event.inputs.Tag_name }} + + - name: Get release + if: ${{ steps.checkTag.outputs.exists == 'true' }} + id: result_release + uses: cardinalby/git-get-release-action@v1 + env: + GITHUB_TOKEN: ${{ secrets.PAT_GITHUB }} + with: + tag: ${{ github.event.inputs.Tag_name }} + repo: REAN-Foundation/reancare-service + + - name: Configure AWS credentials + if: ${{ steps.checkTag.outputs.exists == 'true' }} + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Get ECR Image Tag + if: ${{ steps.checkTag.outputs.exists == 'true' }} + id: imageidvar + run: | + image_tag+=${{ steps.result_release.outputs.tag_name }} && image_tag+=_ && image_tag+=${{ steps.result_release.outputs.id }} + echo "imagetag_value=$(aws ecr-public describe-image-tags --repository-name reancare --region us-east-1 --query "imageTagDetails[?imageTag=='$image_tag'].imageTag" --output text)" >> $GITHUB_OUTPUT + + - name: ECR Image and Github Tag Check + run: | + if [[ ${{ steps.checkTag.outputs.exists }} == 'false' ]]; then exit 1; fi + if [[ -z "${{ steps.imageidvar.outputs.imagetag_value }}" ]]; then exit 1; fi + + outputs: + release_name: ${{ steps.result_release.outputs.tag_name }} + release_id: ${{ steps.result_release.outputs.id }} + + Deploy-ECS: + needs: Github-ECR-Tag-Check + environment: aha-uat + runs-on: ubuntu-latest + + steps: + + - name: Checkout + uses: actions/checkout@v3 + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to Amazon ECR + run: | + aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws + + - name: Cache Docker layers + uses: actions/cache@v3 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Download task definition + run: | + aws ecs describe-task-definition --task-definition ${{ secrets.TASK_DEFINTION_NAME }} \ + --query taskDefinition > task-definition.json + + - name: New image ID in the Amazon ECS task definition + id: task-def + uses: aws-actions/amazon-ecs-render-task-definition@v1 + with: + task-definition: task-definition.json + container-name: default + image: public.ecr.aws/i9y2d4u3/awards-service:${{ needs.Github-ECR-Tag-Check.outputs.release_name }}_${{ needs.Github-ECR-Tag-Check.outputs.release_id }} + + - name: Deploy Amazon ECS task definition + uses: aws-actions/amazon-ecs-deploy-task-definition@v1 + with: + task-definition: ${{ steps.task-def.outputs.task-definition }} + wait-for-service-stability: true + + - name: Task Definition Variable + id: taskdefintionvar + shell: bash + run: | + echo "task_definition_arn=$(aws ecs describe-task-definition --task-definition ${{ secrets.TASK_DEFINTION_NAME }} | jq '.[] | .taskDefinitionArn')" >> $GITHUB_OUTPUT + + - name: Task Defintion ARN + run: | + echo "Task Defintion: ${{ steps.taskdefintionvar.outputs.task_definition_arn }}" + + - name: Deploy Amazon ECS task definition using Duplo API + uses: fjogeleit/http-request-action@master + with: + url: 'https://reanfoundation.duplocloud.net/subscriptions/${{ secrets.DUPLO_ID }}/UpdateEcsService' + method: 'POST' + data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "${{ secrets.SERVICE_NAME }}","Replicas":1, "HealthCheckGracePeriodSeconds": 1200, "DnsPrfx": ""}' + bearerToken: ${{ secrets.DUPLOCLOUD_TOKEN }} From d5401900ac510878ed74b6b143308e8b07afd9ee Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Fri, 23 Jun 2023 12:14:39 +0530 Subject: [PATCH 60/66] Create aha-prod-ci-cd.yml --- .github/workflows/aha-prod-ci-cd.yml | 136 +++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 .github/workflows/aha-prod-ci-cd.yml diff --git a/.github/workflows/aha-prod-ci-cd.yml b/.github/workflows/aha-prod-ci-cd.yml new file mode 100644 index 0000000..90c7455 --- /dev/null +++ b/.github/workflows/aha-prod-ci-cd.yml @@ -0,0 +1,136 @@ +name: AHA-PROD-CI-CD + +# Controls when the workflow will run +on: + # Triggers the workflow on push events but only for the develop branch + workflow_dispatch: + inputs: + Tag_name: + description: Tag name of your release(please include "v" if needed) + required: true + +jobs: + + + Github-ECR-Tag-Check: + runs-on: ubuntu-latest + + steps: + - name: check tag + uses: mukunku/tag-exists-action@v1.2.0 + id: checkTag + with: + tag: ${{ github.event.inputs.Tag_name }} + + - name: Get release + if: ${{ steps.checkTag.outputs.exists == 'true' }} + id: result_release + uses: cardinalby/git-get-release-action@v1 + env: + GITHUB_TOKEN: ${{ secrets.PAT_GITHUB }} + with: + tag: ${{ github.event.inputs.Tag_name }} + repo: REAN-Foundation/awards-service + + - name: Configure AWS credentials + if: ${{ steps.checkTag.outputs.exists == 'true' }} + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Get ECR Image Tag + if: ${{ steps.checkTag.outputs.exists == 'true' }} + id: imageidvar + run: | + image_tag+=${{ steps.result_release.outputs.tag_name }} && image_tag+=_ && image_tag+=${{ steps.result_release.outputs.id }} + echo "imagetag_value=$(aws ecr-public describe-image-tags --repository-name awards-service --region us-east-1 --query "imageTagDetails[?imageTag=='$image_tag'].imageTag" --output text)" >> $GITHUB_OUTPUT + + - name: ECR Image and Github Tag Check + run: | + if [[ ${{ steps.checkTag.outputs.exists }} == 'false' ]]; then exit 1; fi + if [[ -z "${{ steps.imageidvar.outputs.imagetag_value }}" ]]; then exit 1; fi + + outputs: + release_name: ${{ steps.result_release.outputs.tag_name }} + release_id: ${{ steps.result_release.outputs.id }} + + + + Deploy-ECS: + needs: Github-ECR-Tag-Check + environment: aha-prod + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Get release + id: result_release + uses: cardinalby/git-get-release-action@v1 + env: + GITHUB_TOKEN: ${{ secrets.PAT_GITHUB }} + with: + tag: ${{ github.event.inputs.Tag_name }} + repo: REAN-Foundation/awards-service + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to Amazon ECR + run: | + aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws + + - name: Cache Docker layers + uses: actions/cache@v3 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Download task definition + run: | + aws ecs describe-task-definition --task-definition ${{ secrets.TASK_DEFINTION_NAME }} \ + --query taskDefinition > task-definition.json + + - name: New image ID in the Amazon ECS task definition + id: task-def + uses: aws-actions/amazon-ecs-render-task-definition@v1 + with: + task-definition: task-definition.json + container-name: default + image: public.ecr.aws/i9y2d4u3/awards-service:${{ needs.Github-ECR-Tag-Check.outputs.release_name }}_${{ needs.Github-ECR-Tag-Check.outputs.release_id }} + + - name: Deploy Amazon ECS task definition + uses: aws-actions/amazon-ecs-deploy-task-definition@v1 + with: + task-definition: ${{ steps.task-def.outputs.task-definition }} + wait-for-service-stability: true + + - name: Task Definition Variable + id: taskdefintionvar + shell: bash + run: | + echo "task_definition_arn=$(aws ecs describe-task-definition --task-definition ${{ secrets.TASK_DEFINTION_NAME }} | jq '.[] | .taskDefinitionArn')" >> $GITHUB_OUTPUT + + - name: Task Defintion ARN + run: | + echo "Task Defintion: ${{ steps.taskdefintionvar.outputs.task_definition_arn }}" + + - name: Deploy Amazon ECS task definition using Duplo API + uses: fjogeleit/http-request-action@master + with: + url: 'https://reanfoundation.duplocloud.net/subscriptions/${{ secrets.DUPLO_ID }}/UpdateEcsService' + method: 'POST' + data: '{"TaskDefinition":${{ steps.taskdefintionvar.outputs.task_definition_arn }},"Name": "${{ secrets.SERVICE_NAME }}","Replicas":1, "HealthCheckGracePeriodSeconds": 1200, "DnsPrfx": ""}' + bearerToken: ${{ secrets.DUPLOCLOUD_TOKEN }} From b5171945fb8a19f115728ffa6d4958c9229faf46 Mon Sep 17 00:00:00 2001 From: rf-opssupport <84499879+rf-opssupport@users.noreply.github.com> Date: Fri, 23 Jun 2023 12:19:30 +0530 Subject: [PATCH 61/66] Update aha-uat-ci-cd.yml --- .github/workflows/aha-uat-ci-cd.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/aha-uat-ci-cd.yml b/.github/workflows/aha-uat-ci-cd.yml index 11c4235..bd8f32b 100644 --- a/.github/workflows/aha-uat-ci-cd.yml +++ b/.github/workflows/aha-uat-ci-cd.yml @@ -45,7 +45,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.PAT_GITHUB }} with: tag: ${{ github.event.inputs.Tag_name }} - repo: REAN-Foundation/reancare-service + repo: REAN-Foundation/awards-service - name: Configure AWS credentials if: ${{ steps.checkTag.outputs.exists == 'true' }} @@ -60,7 +60,7 @@ jobs: id: imageidvar run: | image_tag+=${{ steps.result_release.outputs.tag_name }} && image_tag+=_ && image_tag+=${{ steps.result_release.outputs.id }} - echo "imagetag_value=$(aws ecr-public describe-image-tags --repository-name reancare --region us-east-1 --query "imageTagDetails[?imageTag=='$image_tag'].imageTag" --output text)" >> $GITHUB_OUTPUT + echo "imagetag_value=$(aws ecr-public describe-image-tags --repository-name awards-service --region us-east-1 --query "imageTagDetails[?imageTag=='$image_tag'].imageTag" --output text)" >> $GITHUB_OUTPUT - name: ECR Image and Github Tag Check run: | From 08756400ef07938e728593626032011e4d7f83a0 Mon Sep 17 00:00:00 2001 From: tabbasum-rean Date: Tue, 27 Jun 2023 12:35:54 +0530 Subject: [PATCH 62/66] Added how to earn badge content --- .../how.to.earn.badge.content.seed..json | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/seed.data/how.to.earn.badge.content.seed..json b/seed.data/how.to.earn.badge.content.seed..json index fb66a89..dd68015 100644 --- a/seed.data/how.to.earn.badge.content.seed..json +++ b/seed.data/how.to.earn.badge.content.seed..json @@ -1,64 +1,62 @@ [ { "Name": "7-Day Medication Adherence", - "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." - + "HowToEarn": "How to earn Medications Badge\n\nEarn a badge for every medications you take.\n\n1. Daily Mark your medication as 'Taken' by swiping left in the Medication Reminders.\nYou can also mark the medication as 'taken' in the To Do's.\n\n2. For 7 consistent days take your medications and earn a badge." }, { "Name": "15-Day Medication Adherence", - "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + "HowToEarn": "How to earn Medications Badge\n\nEarn a badge for every medications you take.\n\n1. Daily Mark your medication as 'Taken' by swiping left in the Medication Reminders.\nYou can also mark the medication as 'taken' in the To Do's.\n\n2. For 15 consistent days take your medications and earn a badge." }, { "Name": "30-Day Medication Adherence", - "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + "HowToEarn": "How to earn Medications Badge\n\nEarn a badge for every medications you take.\n\n1. Daily Mark your medication as 'Taken' by swiping left in the Medication Reminders.\nYou can also mark the medication as 'taken' in the To Do's.\n\n2. For 30 consistent days take your medications and earn a badge." }, { "Name": "7-Day Healthy Nutrition Choice", - "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + "HowToEarn": "How to earn Nutrition Badge\n\nEarn a badge for having health food.\n\n1. Daily Mark Yes on the home screen for the question - Were most of your food choices health today?\n\n2. For 7 consistent days have health food choices and earn a badge." }, { "Name": "15-Day Healthy Nutrition Choice", - "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + "HowToEarn": "How to earn Nutrition Badge\n\nEarn a badge for having health food.\n\n1. Daily Mark Yes on the home screen for the question - Were most of your food choices health today?\n\n2. For 15 consistent days have health food choices and earn a badge." }, { "Name": "30-Day Healthy Nutrition Choice", - "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + "HowToEarn": "How to earn Nutrition Badge\n\nEarn a badge for having health food.\n\n1. Daily Mark Yes on the home screen for the question - Were most of your food choices health today?\n\n2. For 30 consistent days have health food choices and earn a badge." }, { "Name": "7-Day Physical Activity", - "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + "HowToEarn": "How to earn Physical Activity Badge\n\nEarn a badge by adding movement to your day.\n\n1. Daily Mark Yes on the home screen for the question - Did you add movement to your day today?\n\n2. For 7 consistent days add movement to your day and earn a badge." }, { "Name": "15-Day Physical Activity", - "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." - + "HowToEarn": "How to earn Physical Activity Badge\n\nEarn a badge by adding movement to your day.\n\n1. Daily Mark Yes on the home screen for the question - Did you add movement to your day today?\n\n2. For 15 consistent days add movement to your day and earn a badge." }, { "Name": "30-Day Physical Activity", - "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + "HowToEarn": "How to earn Physical Activity Badge\n\nEarn a badge by adding movement to your day.\n\n1. Daily Mark Yes on the home screen for the question - Did you add movement to your day today?\n\n2. For 30 consistent days add movement to your day and earn a badge." }, { "Name": "Mental health 7-Day Badge", - "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + "HowToEarn": "How to earn Mental Well-Being Badge\n\nEarn a badge by practicing mindfulness and recording your sleep.\n\n1. Daily record your Sleep hours or Mindfulness time in the Mental Well-Being section.\n\n2. For 7 consistent days record your sleep and mindfulness time to earn a badge." }, { "Name": "Mental health 15-Day Badge", - "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + "HowToEarn": "How to earn Mental Well-Being Badge\n\nEarn a badge by practicing mindfulness and recording your sleep.\n\n1. Daily record your Sleep hours or Mindfulness time in the Mental Well-Being section.\n\n2. For 15 consistent days record your sleep and mindfulness time to earn a badge." }, { "Name": "Mental health 30-Day Badge", - "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + "HowToEarn": "How to earn Mental Well-Being Badge\n\nEarn a badge by practicing mindfulness and recording your sleep.\n\n1. Daily record your Sleep hours or Mindfulness time in the Mental Well-Being section.\n\n2. For 30 consistent days record your sleep and mindfulness time to earn a badge." }, { "Name": "7-Day Vitals", - "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + "HowToEarn": "How to earn the Vitals Badge\n\nEarn a badge by recording your daily vitals.\n\n1. Daily record your Vitals to get the badge.\n\n2. For 7 consistent days record your vitals to earn a badge." }, { "Name": "15-Day Vitals", - "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + "HowToEarn": "How to earn the Vitals Badge\n\nEarn a badge by recording your daily vitals.\n\n1. Daily record your Vitals to get the badge.\n\n2. For 15 consistent days record your vitals to earn a badge." }, { "Name": "30-Day Vitals", - "HowToEarn": "Once you have successfully logged your medication as taken for the required number of consecutive days, the app should recognize your achievement and award you the badge or reward." + "HowToEarn": "How to earn the Vitals Badge\n\nEarn a badge by recording your daily vitals.\n\n1. Daily record your Vitals to get the badge.\n\n2. For 30 consistent days record your vitals to earn a badge." } ] From 688bac7defbc0e99ade9cdcc65bb2b0cb4562fe8 Mon Sep 17 00:00:00 2001 From: tabbasum-rean Date: Tue, 27 Jun 2023 12:44:25 +0530 Subject: [PATCH 63/66] Fixed linting errors --- src/database/services/awards/badge.service.ts | 2 +- src/startup/seeder.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/database/services/awards/badge.service.ts b/src/database/services/awards/badge.service.ts index e853ea2..7950f1f 100644 --- a/src/database/services/awards/badge.service.ts +++ b/src/database/services/awards/badge.service.ts @@ -81,7 +81,7 @@ export class BadgeService extends BaseService { logger.error(error.message); ErrorHandler.throwInternalServerError(error.message, 500); } - } + }; public search = async (filters: BadgeSearchFilters) : Promise => { diff --git a/src/startup/seeder.ts b/src/startup/seeder.ts index 41d9393..d8a1997 100644 --- a/src/startup/seeder.ts +++ b/src/startup/seeder.ts @@ -238,7 +238,7 @@ export class Seeder { var badgeStockImage = await this._badgeStockImageService.create(domainModel); if (!badgeStockImage) { - console.log('Error occurred while seeding badge stock images!'); + logger.info('Error occurred while seeding badge stock images!'); } } }; From 47abdbd232e4103817fca1ec88f1f126c96f1385 Mon Sep 17 00:00:00 2001 From: tabbasum-rean Date: Tue, 27 Jun 2023 15:27:43 +0530 Subject: [PATCH 64/66] Updated how to earn badge content --- .../how.to.earn.badge.content.seed..json | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/seed.data/how.to.earn.badge.content.seed..json b/seed.data/how.to.earn.badge.content.seed..json index dd68015..34e3602 100644 --- a/seed.data/how.to.earn.badge.content.seed..json +++ b/seed.data/how.to.earn.badge.content.seed..json @@ -1,62 +1,62 @@ [ { "Name": "7-Day Medication Adherence", - "HowToEarn": "How to earn Medications Badge\n\nEarn a badge for every medications you take.\n\n1. Daily Mark your medication as 'Taken' by swiping left in the Medication Reminders.\nYou can also mark the medication as 'taken' in the To Do's.\n\n2. For 7 consistent days take your medications and earn a badge." + "HowToEarn": "Earn a badge for every medications you take.\n\n1. Daily Mark your medication as 'Taken' by swiping left in the Medication Reminders.\nYou can also mark the medication as 'taken' in the To Do's.\n\n2. For 7 consistent days take your medications and earn a badge." }, { "Name": "15-Day Medication Adherence", - "HowToEarn": "How to earn Medications Badge\n\nEarn a badge for every medications you take.\n\n1. Daily Mark your medication as 'Taken' by swiping left in the Medication Reminders.\nYou can also mark the medication as 'taken' in the To Do's.\n\n2. For 15 consistent days take your medications and earn a badge." + "HowToEarn": "Earn a badge for every medications you take.\n\n1. Daily Mark your medication as 'Taken' by swiping left in the Medication Reminders.\nYou can also mark the medication as 'taken' in the To Do's.\n\n2. For 15 consistent days take your medications and earn a badge." }, { "Name": "30-Day Medication Adherence", - "HowToEarn": "How to earn Medications Badge\n\nEarn a badge for every medications you take.\n\n1. Daily Mark your medication as 'Taken' by swiping left in the Medication Reminders.\nYou can also mark the medication as 'taken' in the To Do's.\n\n2. For 30 consistent days take your medications and earn a badge." + "HowToEarn": "Earn a badge for every medications you take.\n\n1. Daily Mark your medication as 'Taken' by swiping left in the Medication Reminders.\nYou can also mark the medication as 'taken' in the To Do's.\n\n2. For 30 consistent days take your medications and earn a badge." }, { "Name": "7-Day Healthy Nutrition Choice", - "HowToEarn": "How to earn Nutrition Badge\n\nEarn a badge for having health food.\n\n1. Daily Mark Yes on the home screen for the question - Were most of your food choices health today?\n\n2. For 7 consistent days have health food choices and earn a badge." + "HowToEarn": "Earn a badge for having health food.\n\n1. Daily Mark Yes on the home screen for the question - Were most of your food choices health today?\n\n2. For 7 consistent days have health food choices and earn a badge." }, { "Name": "15-Day Healthy Nutrition Choice", - "HowToEarn": "How to earn Nutrition Badge\n\nEarn a badge for having health food.\n\n1. Daily Mark Yes on the home screen for the question - Were most of your food choices health today?\n\n2. For 15 consistent days have health food choices and earn a badge." + "HowToEarn": "Earn a badge for having health food.\n\n1. Daily Mark Yes on the home screen for the question - Were most of your food choices health today?\n\n2. For 15 consistent days have health food choices and earn a badge." }, { "Name": "30-Day Healthy Nutrition Choice", - "HowToEarn": "How to earn Nutrition Badge\n\nEarn a badge for having health food.\n\n1. Daily Mark Yes on the home screen for the question - Were most of your food choices health today?\n\n2. For 30 consistent days have health food choices and earn a badge." + "HowToEarn": "Earn a badge for having health food.\n\n1. Daily Mark Yes on the home screen for the question - Were most of your food choices health today?\n\n2. For 30 consistent days have health food choices and earn a badge." }, { "Name": "7-Day Physical Activity", - "HowToEarn": "How to earn Physical Activity Badge\n\nEarn a badge by adding movement to your day.\n\n1. Daily Mark Yes on the home screen for the question - Did you add movement to your day today?\n\n2. For 7 consistent days add movement to your day and earn a badge." + "HowToEarn": "Earn a badge by adding movement to your day.\n\n1. Daily Mark Yes on the home screen for the question - Did you add movement to your day today?\n\n2. For 7 consistent days add movement to your day and earn a badge." }, { "Name": "15-Day Physical Activity", - "HowToEarn": "How to earn Physical Activity Badge\n\nEarn a badge by adding movement to your day.\n\n1. Daily Mark Yes on the home screen for the question - Did you add movement to your day today?\n\n2. For 15 consistent days add movement to your day and earn a badge." + "HowToEarn": "Earn a badge by adding movement to your day.\n\n1. Daily Mark Yes on the home screen for the question - Did you add movement to your day today?\n\n2. For 15 consistent days add movement to your day and earn a badge." }, { "Name": "30-Day Physical Activity", - "HowToEarn": "How to earn Physical Activity Badge\n\nEarn a badge by adding movement to your day.\n\n1. Daily Mark Yes on the home screen for the question - Did you add movement to your day today?\n\n2. For 30 consistent days add movement to your day and earn a badge." + "HowToEarn": "Earn a badge by adding movement to your day.\n\n1. Daily Mark Yes on the home screen for the question - Did you add movement to your day today?\n\n2. For 30 consistent days add movement to your day and earn a badge." }, { "Name": "Mental health 7-Day Badge", - "HowToEarn": "How to earn Mental Well-Being Badge\n\nEarn a badge by practicing mindfulness and recording your sleep.\n\n1. Daily record your Sleep hours or Mindfulness time in the Mental Well-Being section.\n\n2. For 7 consistent days record your sleep and mindfulness time to earn a badge." + "HowToEarn": "Earn a badge by practicing mindfulness and recording your sleep.\n\n1. Daily record your Sleep hours or Mindfulness time in the Mental Well-Being section.\n\n2. For 7 consistent days record your sleep and mindfulness time to earn a badge." }, { "Name": "Mental health 15-Day Badge", - "HowToEarn": "How to earn Mental Well-Being Badge\n\nEarn a badge by practicing mindfulness and recording your sleep.\n\n1. Daily record your Sleep hours or Mindfulness time in the Mental Well-Being section.\n\n2. For 15 consistent days record your sleep and mindfulness time to earn a badge." + "HowToEarn": "Earn a badge by practicing mindfulness and recording your sleep.\n\n1. Daily record your Sleep hours or Mindfulness time in the Mental Well-Being section.\n\n2. For 15 consistent days record your sleep and mindfulness time to earn a badge." }, { "Name": "Mental health 30-Day Badge", - "HowToEarn": "How to earn Mental Well-Being Badge\n\nEarn a badge by practicing mindfulness and recording your sleep.\n\n1. Daily record your Sleep hours or Mindfulness time in the Mental Well-Being section.\n\n2. For 30 consistent days record your sleep and mindfulness time to earn a badge." + "HowToEarn": "Earn a badge by practicing mindfulness and recording your sleep.\n\n1. Daily record your Sleep hours or Mindfulness time in the Mental Well-Being section.\n\n2. For 30 consistent days record your sleep and mindfulness time to earn a badge." }, { "Name": "7-Day Vitals", - "HowToEarn": "How to earn the Vitals Badge\n\nEarn a badge by recording your daily vitals.\n\n1. Daily record your Vitals to get the badge.\n\n2. For 7 consistent days record your vitals to earn a badge." + "HowToEarn": "Earn a badge by recording your daily vitals.\n\n1. Daily record your Vitals to get the badge.\n\n2. For 7 consistent days record your vitals to earn a badge." }, { "Name": "15-Day Vitals", - "HowToEarn": "How to earn the Vitals Badge\n\nEarn a badge by recording your daily vitals.\n\n1. Daily record your Vitals to get the badge.\n\n2. For 15 consistent days record your vitals to earn a badge." + "HowToEarn": "Earn a badge by recording your daily vitals.\n\n1. Daily record your Vitals to get the badge.\n\n2. For 15 consistent days record your vitals to earn a badge." }, { "Name": "30-Day Vitals", - "HowToEarn": "How to earn the Vitals Badge\n\nEarn a badge by recording your daily vitals.\n\n1. Daily record your Vitals to get the badge.\n\n2. For 30 consistent days record your vitals to earn a badge." + "HowToEarn": "Earn a badge by recording your daily vitals.\n\n1. Daily record your Vitals to get the badge.\n\n2. For 30 consistent days record your vitals to earn a badge." } ] From af90d9b6f453696c1f10d3b1380709872538c8e3 Mon Sep 17 00:00:00 2001 From: vinay-debug <84920398+vinay-debug@users.noreply.github.com> Date: Thu, 6 Jul 2023 12:29:23 +0530 Subject: [PATCH 65/66] Medication award fact model updated --- .../fact.extractors/models/medication.fact.model.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/modules/fact.extractors/models/medication.fact.model.ts b/src/modules/fact.extractors/models/medication.fact.model.ts index 4329a39..3931f09 100644 --- a/src/modules/fact.extractors/models/medication.fact.model.ts +++ b/src/modules/fact.extractors/models/medication.fact.model.ts @@ -34,4 +34,12 @@ export class MedicationFact { @Column({ nullable: true }) RecordDateStr : string; + @Column({ + type : 'varchar', + length : 16, + nullable : false, + default : '+05:30', + }) + RecordTimeZone: string; + } From eacecbb5f61e403f111d76d71fd31c016a425b63 Mon Sep 17 00:00:00 2001 From: vinay-debug <84920398+vinay-debug@users.noreply.github.com> Date: Fri, 7 Jul 2023 11:11:51 +0530 Subject: [PATCH 66/66] added time zone column in all badge fact model --- .../models/exercise.physical.activity.fact.model.ts | 8 ++++++++ .../fact.extractors/models/mental.health.fact.model.ts | 8 ++++++++ .../fact.extractors/models/nutrition.choice.fact.model.ts | 8 ++++++++ src/modules/fact.extractors/models/vital.fact.model.ts | 8 ++++++++ 4 files changed, 32 insertions(+) diff --git a/src/modules/fact.extractors/models/exercise.physical.activity.fact.model.ts b/src/modules/fact.extractors/models/exercise.physical.activity.fact.model.ts index 99a924d..1983098 100644 --- a/src/modules/fact.extractors/models/exercise.physical.activity.fact.model.ts +++ b/src/modules/fact.extractors/models/exercise.physical.activity.fact.model.ts @@ -28,4 +28,12 @@ export class ExercisePhysicalActivityFact { @Column({ nullable: true }) RecordDateStr : string; + @Column({ + type : 'varchar', + length : 16, + nullable : false, + default : '+05:30', + }) + RecordTimeZone: string; + } diff --git a/src/modules/fact.extractors/models/mental.health.fact.model.ts b/src/modules/fact.extractors/models/mental.health.fact.model.ts index d1c1630..1bee7fe 100644 --- a/src/modules/fact.extractors/models/mental.health.fact.model.ts +++ b/src/modules/fact.extractors/models/mental.health.fact.model.ts @@ -34,4 +34,12 @@ export class MentalHealthFact { @Column({ nullable: true }) RecordDateStr : string; + @Column({ + type : 'varchar', + length : 16, + nullable : false, + default : '+05:30', + }) + RecordTimeZone: string; + } diff --git a/src/modules/fact.extractors/models/nutrition.choice.fact.model.ts b/src/modules/fact.extractors/models/nutrition.choice.fact.model.ts index bcfdde4..278d83a 100644 --- a/src/modules/fact.extractors/models/nutrition.choice.fact.model.ts +++ b/src/modules/fact.extractors/models/nutrition.choice.fact.model.ts @@ -28,4 +28,12 @@ export class NutritionChoiceFact { @Column({ nullable: true }) RecordDateStr : string; + @Column({ + type : 'varchar', + length : 16, + nullable : false, + default : '+05:30', + }) + RecordTimeZone: string; + } diff --git a/src/modules/fact.extractors/models/vital.fact.model.ts b/src/modules/fact.extractors/models/vital.fact.model.ts index 36123ad..9d42c9e 100644 --- a/src/modules/fact.extractors/models/vital.fact.model.ts +++ b/src/modules/fact.extractors/models/vital.fact.model.ts @@ -38,4 +38,12 @@ export class VitalFact { @Column({ nullable: true }) RecordDateStr: string; + @Column({ + type : 'varchar', + length : 16, + nullable : false, + default : '+05:30', + }) + RecordTimeZone: string; + }