From bb69cbceff866c5d6eb4c85e9a902128d44c4222 Mon Sep 17 00:00:00 2001 From: Loise Kwirica <93908695+kwirica@users.noreply.github.com> Date: Thu, 28 Sep 2023 14:29:31 +0300 Subject: [PATCH 1/2] Editing the docs to reflect the installation process using ansible --- docs/developer_guide/gofr_installation.md | 340 ++++++++++++++++++ docs/developer_guide/server_administration.md | 293 +-------------- mkdocs.yml | 1 + 3 files changed, 343 insertions(+), 291 deletions(-) create mode 100644 docs/developer_guide/gofr_installation.md diff --git a/docs/developer_guide/gofr_installation.md b/docs/developer_guide/gofr_installation.md new file mode 100644 index 00000000..a643e983 --- /dev/null +++ b/docs/developer_guide/gofr_installation.md @@ -0,0 +1,340 @@ +# How to install GOFR + +## GOFR Installation + +### 1. Install redis + + sudo apt install redis + +### 2. Install tomcat + + sudo apt install tomcat9 + +### 3. Install postgres (version 9.3 or above) + +### 4. Install HAPI FHIR + +#### a) Create Database + + sudo -u postgres psql + create database hapi; + create user hapi with encrypted password 'PASS'; + grant all privileges on database hapi to hapi; + \q + +#### b) Install maven to compile hapi + + sudo apt install maven + git clone + cd hapi-fhir-jpaserver-starter + + Edit pom.xml and change the following line from hapi-fhir-jpaserver: + + hapi + + Edit src/main/resources/application.yaml and change the following + + spring.datasource.url=’jdbc:postgresql://localhost:5432/hapi’ + spring.datasource.username=’hapi’ + spring.datasource.password=’PASS’ + spring.datasource.driverClassName=’org.postgresql.Driver’ + + Uncomment below lines + + # hibernate.search.enabled: true + + # hibernate.search.backend.type: lucene + + # hibernate.search.backend.analysis.configurer: ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer + + # hibernate.search.backend.directory.type: local-filesystem + + # hibernate.search.backend.directory.root: target/lucenefiles + + # hibernate.search.backend.lucene_version: lucene_current + + auto_create_placeholder_reference_targets=true + hapi.fhir.enable_index_missing_fields=true + hapi.fhir.client_id_strategy=ANY + + Uncomment below lines + + # partitioning + + # allow_references_across_partitions: false + + # partitioning_include_in_search_hashes: false + + Create war file + + mvn clean install -DskipTests + sudo mkdir /var/lib/tomcat9/target + sudo chown tomcat:tomcat /var/lib/tomcat9/target + sudo cp target/hapi.war /var/lib/tomcat9/webapps + +#### c) Load Basic Definitions + + Download and install hapi-fhir-cli: here

+ + Load definitions with below commands ./hapi-fhir-cli upload-definitions -v r4 -t here

+ +### 5. Keycloak Installation + + !!! Important "Install keycloak only if you want to use it as an identity provider." + + Follow instructions here

+ +### 6. Keycloak Configuration + + Modify keycloak base URL to keycloak/auth by changing web-context in standalone/configuration/standalone.xml to keycloak/auth. + + This will make keycloak accessible via + + Copy GOFR keycloak theme to keycloak + + cp -r gofr/resources/keycloak/themes/gofr keycloak/themes/ + + Load GOFR keycloak realm + + Before loading the realm, make sure that Keycloak is running, if not running, please use below command to start it + + bin/standalone.sh + + To load the realm, first login to keycloak by running below command + + ./kcadm.sh config credentials --server --realm master --user admin --password admin + + where **username** and **password** refers to an admin account that has access to the master realm + + Now load the GOFR keycloak realm with below command + + ./kcadm.sh create realms -f gofr/resources/keycloak/realm.json_ + +### 7. Clone GOFR github repository + + git clone + +### 8. Install dependencies + + cd gofr/gofr-backend + npm install + +### 9 Running GOFR in production mode + + cd gofr/gofr-backend/lib + node app.js + +### 10. Accessing GOFR + + + + +Install redis. +```sh +sudo apt install redis +``` +Install tomcat. +```sh +sudo apt install tomcat9 +``` +Install postgres (version 9.3 or above) + +Install HAPI FHIR + +Create database +```pgsql +sudo -u postgres psql +create database hapi; +create user hapi with encrypted password 'PASS'; +grant all privileges on database hapi to hapi; +\q +``` + +Install maven to compile hapi +```sh +sudo apt install maven +``` + +```sh +git clone https://github.com/hapifhir/hapi-fhir-jpaserver-starter.git +cd hapi-fhir-jpaserver-starter +``` + +Edit pom.xml and change the following line from hapi-fhir-jpaserver: +```xml +hapi +``` + +Edit src/main/resources/application.yaml and change the following +```yaml +spring.datasource.url=’jdbc:postgresql://localhost:5432/hapi’ +spring.datasource.username=’hapi’ +spring.datasource.password=’PASS’ +spring.datasource.driverClassName=’org.postgresql.Driver’ +# Uncomment below lines +# hibernate.search.enabled: true +# hibernate.search.backend.type: lucene +# hibernate.search.backend.analysis.configurer: ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer +# hibernate.search.backend.directory.type: local-filesystem +# hibernate.search.backend.directory.root: target/lucenefiles +# hibernate.search.backend.lucene_version: lucene_current + +auto_create_placeholder_reference_targets=true +hapi.fhir.enable_index_missing_fields=true +hapi.fhir.client_id_strategy=ANY +# Uncomment below lines +# partitioning: + # allow_references_across_partitions: false + # partitioning_include_in_search_hashes: false +``` + +Create war file +``` +mvn clean install -DskipTests +sudo mkdir /var/lib/tomcat9/target +sudo chown tomcat:tomcat /var/lib/tomcat9/target +sudo cp target/hapi.war /var/lib/tomcat9/webapps +``` + +Load Basic Definitions +* Download and install hapi-fhir-cli: here https://hapifhir.io/hapi-fhir/docs/tools/hapi_fhir_cli.html +* Load definitions with below commands `./hapi-fhir-cli upload-definitions -v r4 -t http://localhost:8080/hapi/fhir/` + + + + +## Introduction to Key Cloak + +**Keycloak** is a **single sign on solution** for web apps such as the **Global Open Facilities Registry system (GOFR)** and other RESTful web services. + +The goal of **Keycloak** is to make security simple so that it is easy for application developers to secure the apps and services they have deployed in their organization. + +Security features that developers normally have to write for themselves are provided out of the box and are easily tailorable to the individual requirements of your organization. + +**Keycloak** provides **customizable user interfaces** for login, registration, administration, and account management. + +You can also use Keycloak as an **integration platform** to hook it into existing LDAP and Active Directory servers. + +You can also **delegate authentication** to third party identity providers like Facebook and Google. + +

For more information about Keycloak see Developer guide

+ +## Setting up Keycloak for GOFR + +The initial server configuration includes an administrator account assigned the **administrator** role in keycloak by default. + +This account and password should be immediately changed after installation. + +!!! important " Install keycloak only if you want to use it as an identity provider. Follow instructions here to install keycloak." + + + Modify keycloak base URL to keycloak/auth by changing web-context in standalone/configuration/standalone.xml to keycloak/auth. + + This will make keycloak accessible via + + Copy GOFR keycloak theme to keycloak + + cp -r gofr/resources/keycloak/themes/gofr keycloak/themes/ + + Load GOFR keycloak realm + + Before loading the realm, make sure that Keycloak is running, if not running, please use below command to start it + + bin/standalone.sh + +To load the realm, first login to keycloak by running below command where username and password refers to an admin account that has access to the master realm + + To load the realm, first login to keycloak by running below command + + ./kcadm.sh config credentials --server --realm master --user admin --password admin + + where **username** and **password** refers to an admin account that has access to the master realm + + Now load the GOFR keycloak realm with below command + + ./kcadm.sh create realms -f gofr/resources/keycloak/realm.json_ + +Clone GOFR github repository +``` +git clone https://github.com/intrahealth/gofr.git +``` + +Install dependencies +``` +cd gofr/gofr-backend +npm install +``` + +Running GOFR in production mode +``` +cd gofr/gofr-backend/lib +node app.js +``` +Access GOFR at: http://localhost:4000 + +## Running GOFR in Development Mode + + Install UI dependencies + + cd gofr/gofr-gui + npm install + + Start the UI + + cd gofr/gofr-gui + npm run serve + + Start the backend + + cd gofr/gofr-backend/lib + node app.js + +## GOFR installation using Ansible + +### Install Ansible + +#### CentOS + +To run gofr on **CentOS** you will need to run the commands below: + + sudo apt install epel-release + +Then: + + sudo yum install epel-release + +And finally: + + sudo yum install ansible + +#### Ubuntu + +When using **Ubuntu** : + +1. Run the commands below: + + sudo apt install Ansible + +2. Edit **/etc/ansible/hosts** and add **127.0.0.1** + +3. Install Ansible modules : + + + ansible-galaxy collection install ansible.utils + ansible-galaxy collection install community.postgresql + +4. clone gofr with command: + + git clone https://github.com/intrahealth/gofr.git + +5. change dir to Ansible + + cd gofr/packaging/ansible + +Depending on your operating system, change **dir** to the OS folder i.e if you are using **Ubuntu**, change to ubuntu as below: + + cd ubuntu + +Start installation by executing the **run.sh** + + sudo bash run.sh \ No newline at end of file diff --git a/docs/developer_guide/server_administration.md b/docs/developer_guide/server_administration.md index 59952ff4..570e4b03 100644 --- a/docs/developer_guide/server_administration.md +++ b/docs/developer_guide/server_administration.md @@ -1,295 +1,6 @@ -# Server administration +# Configuration Parameters -## GOFR Installation - -### 1. Install redis - - sudo apt install redis - -### 2. Install tomcat - - sudo apt install tomcat9 - -### 3. Install postgres (version 9.3 or above) - -### 4. Install HAPI FHIR - -#### a) Create Database - - sudo -u postgres psql - create database hapi; - create user hapi with encrypted password 'PASS'; - grant all privileges on database hapi to hapi; - \q - -#### b) Install maven to compile hapi - - sudo apt install maven - git clone - cd hapi-fhir-jpaserver-starter - - Edit pom.xml and change the following line from hapi-fhir-jpaserver: - - hapi - - Edit src/main/resources/application.yaml and change the following - - spring.datasource.url=’jdbc:postgresql://localhost:5432/hapi’ - spring.datasource.username=’hapi’ - spring.datasource.password=’PASS’ - spring.datasource.driverClassName=’org.postgresql.Driver’ - - Uncomment below lines - - # hibernate.search.enabled: true - - # hibernate.search.backend.type: lucene - - # hibernate.search.backend.analysis.configurer: ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer - - # hibernate.search.backend.directory.type: local-filesystem - - # hibernate.search.backend.directory.root: target/lucenefiles - - # hibernate.search.backend.lucene_version: lucene_current - - auto_create_placeholder_reference_targets=true - hapi.fhir.enable_index_missing_fields=true - hapi.fhir.client_id_strategy=ANY - - Uncomment below lines - - # partitioning - - # allow_references_across_partitions: false - - # partitioning_include_in_search_hashes: false - - Create war file - - mvn clean install -DskipTests - sudo mkdir /var/lib/tomcat9/target - sudo chown tomcat:tomcat /var/lib/tomcat9/target - sudo cp target/hapi.war /var/lib/tomcat9/webapps - -#### c) Load Basic Definitions - - Download and install hapi-fhir-cli: here

- - Load definitions with below commands ./hapi-fhir-cli upload-definitions -v r4 -t here

- -### 5. Keycloak Installation - - !!! Important "Install keycloak only if you want to use it as an identity provider." - - Follow instructions here

- -### 6. Keycloak Configuration - - Modify keycloak base URL to keycloak/auth by changing web-context in standalone/configuration/standalone.xml to keycloak/auth. - - This will make keycloak accessible via - - Copy GOFR keycloak theme to keycloak - - cp -r gofr/resources/keycloak/themes/gofr keycloak/themes/ - - Load GOFR keycloak realm - - Before loading the realm, make sure that Keycloak is running, if not running, please use below command to start it - - bin/standalone.sh - - To load the realm, first login to keycloak by running below command - - ./kcadm.sh config credentials --server --realm master --user admin --password admin - - where **username** and **password** refers to an admin account that has access to the master realm - - Now load the GOFR keycloak realm with below command - - ./kcadm.sh create realms -f gofr/resources/keycloak/realm.json_ - -### 7. Clone GOFR github repository - - git clone - -### 8. Install dependencies - - cd gofr/gofr-backend - npm install - -### 9 Running GOFR in production mode - - cd gofr/gofr-backend/lib - node app.js - -### 10. Accessing GOFR - - - - -Install redis. -```sh -sudo apt install redis -``` -Install tomcat. -```sh -sudo apt install tomcat9 -``` -Install postgres (version 9.3 or above) - -Install HAPI FHIR - -Create database -```pgsql -sudo -u postgres psql -create database hapi; -create user hapi with encrypted password 'PASS'; -grant all privileges on database hapi to hapi; -\q -``` - -Install maven to compile hapi -```sh -sudo apt install maven -``` - -```sh -git clone https://github.com/hapifhir/hapi-fhir-jpaserver-starter.git -cd hapi-fhir-jpaserver-starter -``` - -Edit pom.xml and change the following line from hapi-fhir-jpaserver: -```xml -hapi -``` - -Edit src/main/resources/application.yaml and change the following -```yaml -spring.datasource.url=’jdbc:postgresql://localhost:5432/hapi’ -spring.datasource.username=’hapi’ -spring.datasource.password=’PASS’ -spring.datasource.driverClassName=’org.postgresql.Driver’ -# Uncomment below lines -# hibernate.search.enabled: true -# hibernate.search.backend.type: lucene -# hibernate.search.backend.analysis.configurer: ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer -# hibernate.search.backend.directory.type: local-filesystem -# hibernate.search.backend.directory.root: target/lucenefiles -# hibernate.search.backend.lucene_version: lucene_current - -auto_create_placeholder_reference_targets=true -hapi.fhir.enable_index_missing_fields=true -hapi.fhir.client_id_strategy=ANY -# Uncomment below lines -# partitioning: - # allow_references_across_partitions: false - # partitioning_include_in_search_hashes: false -``` - -Create war file -``` -mvn clean install -DskipTests -sudo mkdir /var/lib/tomcat9/target -sudo chown tomcat:tomcat /var/lib/tomcat9/target -sudo cp target/hapi.war /var/lib/tomcat9/webapps -``` - -Load Basic Definitions -* Download and install hapi-fhir-cli: here https://hapifhir.io/hapi-fhir/docs/tools/hapi_fhir_cli.html -* Load definitions with below commands `./hapi-fhir-cli upload-definitions -v r4 -t http://localhost:8080/hapi/fhir/` - - - - -## Introduction to Key Cloak - -**Keycloak** is a **single sign on solution** for web apps such as the **Global Open Facilities Registry system (GOFR)** and other RESTful web services. - -The goal of **Keycloak** is to make security simple so that it is easy for application developers to secure the apps and services they have deployed in their organization. - -Security features that developers normally have to write for themselves are provided out of the box and are easily tailorable to the individual requirements of your organization. - -**Keycloak** provides **customizable user interfaces** for login, registration, administration, and account management. - -You can also use Keycloak as an **integration platform** to hook it into existing LDAP and Active Directory servers. - -You can also **delegate authentication** to third party identity providers like Facebook and Google. - -

For more information about Keycloak see Developer guide

- -## Setting up Keycloak for GOFR - -The initial server configuration includes an administrator account assigned the **administrator** role in keycloak by default. - -This account and password should be immediately changed after installation. - -!!! important " Install keycloak only if you want to use it as an identity provider. Follow instructions here to install keycloak." - - - Modify keycloak base URL to keycloak/auth by changing web-context in standalone/configuration/standalone.xml to keycloak/auth. - - This will make keycloak accessible via - - Copy GOFR keycloak theme to keycloak - - cp -r gofr/resources/keycloak/themes/gofr keycloak/themes/ - - Load GOFR keycloak realm - - Before loading the realm, make sure that Keycloak is running, if not running, please use below command to start it - - bin/standalone.sh - -To load the realm, first login to keycloak by running below command where username and password refers to an admin account that has access to the master realm - - To load the realm, first login to keycloak by running below command - - ./kcadm.sh config credentials --server --realm master --user admin --password admin - - where **username** and **password** refers to an admin account that has access to the master realm - - Now load the GOFR keycloak realm with below command - - ./kcadm.sh create realms -f gofr/resources/keycloak/realm.json_ - -Clone GOFR github repository -``` -git clone https://github.com/intrahealth/gofr.git -``` - -Install dependencies -``` -cd gofr/gofr-backend -npm install -``` - -Running GOFR in production mode -``` -cd gofr/gofr-backend/lib -node app.js -``` -Access GOFR at: http://localhost:4000 - -## Running GOFR in Development Mode - - Install UI dependencies - - cd gofr/gofr-gui - npm install - - Start the UI - - cd gofr/gofr-gui - npm run serve - - Start the backend - - cd gofr/gofr-backend/lib - node app.js - -## Configuration Parameters +The following are the various configurations for GoFR **a) app.installed** diff --git a/mkdocs.yml b/mkdocs.yml index 8d823ea3..d67a174c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -51,6 +51,7 @@ nav: - developer_guide/mcsd.md - developer_guide/forms.md - developer_guide/ansible.md + - developer_guide/gofr_installation.md - developer_guide/server_administration.md markdown_extensions: From 78f1e4d3972e3717c6d59ca1965751d79a8b6d84 Mon Sep 17 00:00:00 2001 From: Muluken Bogale Date: Wed, 6 Dec 2023 10:29:11 +0300 Subject: [PATCH 2/2] setup test and add test modules --- .gitignore | 5 +- gofr-backend/.gitignore | 1 + gofr-backend/__tests__/config.test.js | 115 +++++++ gofr-backend/__tests__/config/default.json | 12 +- gofr-backend/__tests__/route-config-test.js | 5 - gofr-backend/__tests__/route.auth.test.js | 119 +++++++ gofr-backend/__tests__/route.fhir.test.js | 355 ++++++++++++++++++++ gofr-backend/jest.config.js | 3 +- gofr-backend/lib/routes/fhir.js | 23 +- gofr-backend/lib/routes/passportAuth.js | 3 +- gofr-backend/package.json | 1 + 11 files changed, 626 insertions(+), 16 deletions(-) create mode 100644 gofr-backend/__tests__/config.test.js delete mode 100644 gofr-backend/__tests__/route-config-test.js create mode 100644 gofr-backend/__tests__/route.auth.test.js create mode 100644 gofr-backend/__tests__/route.fhir.test.js diff --git a/.gitignore b/.gitignore index 3cdeabcd..c4be777f 100644 --- a/.gitignore +++ b/.gitignore @@ -31,4 +31,7 @@ tests/node_modules tests/screenshot* # notebooks -.ipynb_checkpoints \ No newline at end of file +.ipynb_checkpoints + +/.idea +/log \ No newline at end of file diff --git a/gofr-backend/.gitignore b/gofr-backend/.gitignore index e812639c..afb80b1e 100644 --- a/gofr-backend/.gitignore +++ b/gofr-backend/.gitignore @@ -1,2 +1,3 @@ /node_modules lib/dbArhives +/coverage diff --git a/gofr-backend/__tests__/config.test.js b/gofr-backend/__tests__/config.test.js new file mode 100644 index 00000000..fafb6cc8 --- /dev/null +++ b/gofr-backend/__tests__/config.test.js @@ -0,0 +1,115 @@ +'use strict' + +const nconf = require('nconf') +const path = require('path') +const configFilePath = path.join(__dirname, "./config/default.json") +nconf.file({file: configFilePath}) + +const testConfig = nconf.get('test') + +const jest_setup = require('../jest-setup') +const config = require("../lib/config"); +jest.mock('axios') + +const DEFAULT_URL = `${testConfig.DEFAULT_URL}/` + +describe('Loads nconf plus base config', () => { + const CONFIG_FILE_OUTPUT = { + "keys": {"gofr": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdeFrJr76IQ+SYAoAIw8crZKNW\nir2re7Z7Iu+XzeYYop5+36Ux6uEQKSXo7s1xY2ou9nCkVAddZ1qehBo0e2MCtk62\nmQJbBT18fiZ3veQPvb0LC/9aFl64RuOguPrCZC+sbZLegQ6Wwf96UWyqmR49gaHO\nEdXwdFdSVyBGyS7dmwIDAQAB\n-----END PUBLIC KEY-----"}, + "additionalConfig": {"gofr-config": "gofr-config"}, + "mCSD": { + "server": { + "protocal": "http", + "host": "localhost", + "port": "8090", + "basePath": "fhir", + "username": "", + "password": "" + }, + "fakeOrgId": "eac583d2-d1ba-11e8-a8d5-f2801f1b9fd1", + "fakeOrgName": "Taifafeki", + "cacheTime": 1200, + "registryDB": "DEFAULT" + }, + } + + const CONFIG_FULL_OUTPUT = { + "additionalConfig": { + "gofr-config": "gofr-config" + }, "keys": { + "gofr": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdeFrJr76IQ+SYAoAIw8crZKNW\nir2re7Z7Iu+XzeYYop5+36Ux6uEQKSXo7s1xY2ou9nCkVAddZ1qehBo0e2MCtk62\nmQJbBT18fiZ3veQPvb0LC/9aFl64RuOguPrCZC+sbZLegQ6Wwf96UWyqmR49gaHO\nEdXwdFdSVyBGyS7dmwIDAQAB\n-----END PUBLIC KEY-----" + }, "mCSD": { + "server": { + "protocal": "http", + "host": "localhost", + "port": "8090", + "basePath": "fhir", + "username": "", + "password": "" + }, + "fakeOrgId": "eac583d2-d1ba-11e8-a8d5-f2801f1b9fd1", + "fakeOrgName": "Taifafeki", + "cacheTime": 1200, + "registryDB": "DEFAULT" + }, + } + + const MOCK_FHIR_OBJECT = { + "resourceType": "Parameters", "id": "gofr-config", "meta": { + "profile": ["http://gofr.org/fhir/StructureDefinition/gofr-parameters-remote-config"] + }, "parameter": [{ + "name": "signature", "valueSignature": { + "type": [{ + "code": "1.2.840.10065.1.12.1.14", "system": "urn:iso-astm:E1762-95:2013" + }], + "when": "2022-09-20T03:44:20.575Z", + "who": { + "reference": "http://gofr.org/fhir/Organization/gofr" + }, + "data": "Td3sLJzy//AlrMy/w+FMYkv1V2zd7vro0+sQiQK32CwXun1B9MYMTLLA214BWsOmnUhi82Dojo3Jn3U2GpPf0BCu47wlln1weYsLA169HDLkG50ch89p3YZ87TyNiNidctCaAHAQ4gz8W+X20szMZeqTkOy/EoEGW0+GuPNGbpw=" + } + }, { + "name": "config", "part": [{ + "name": "site:title", "valueString": "Manage" + }, { + "name": "site:site", "valueString": "Demo" + }, { + "name": "site:logo", "valueString": "iHRIS5Logo.png" + }] + }] + } + + beforeEach(() => { + require('axios').__setFhirResults(DEFAULT_URL + "Parameters/gofr-config", null, MOCK_FHIR_OBJECT) + }) + + test('Check if object contains required properties', () => { + let additionalConfig = config.get('additionalConfig') + let keys = config.get('keys') + let appConfig = config.get('app') + expect(additionalConfig).toHaveProperty('gofr-config') + expect(keys).toHaveProperty('gofr') + expect(appConfig).toHaveProperty('site'); + expect(appConfig.site).toHaveProperty('path'); + expect(appConfig).toHaveProperty('core'); + expect(appConfig.core).toHaveProperty('path'); + }) + + test('loads default config from mock file and mock fhir server', () => { + const nconf = require('../lib/config') + let config = { + additionalConfig: nconf.get('additionalConfig'), keys: nconf.get('keys'), mCSD: nconf.get('mCSD') + } + expect(config).toEqual(CONFIG_FILE_OUTPUT) + }) + + test('loads default config and remote config from mock fhir server', () => { + const nconf = require('../lib/config') + return nconf.loadRemote().then(() => { + let config = { + additionalConfig: nconf.get('additionalConfig'), keys: nconf.get('keys'), mCSD: nconf.get('mCSD') + } + expect(config).toEqual(CONFIG_FULL_OUTPUT) + }) + }) +}) diff --git a/gofr-backend/__tests__/config/default.json b/gofr-backend/__tests__/config/default.json index 17fe04bf..caf7bd5d 100644 --- a/gofr-backend/__tests__/config/default.json +++ b/gofr-backend/__tests__/config/default.json @@ -10,7 +10,7 @@ "idp": "dhis2", "version": "2.2.0", "site": { - "path": "/home/ally/gofr/gofr-backend/lib/gofr-backend-site", + "path": "/home/pc/Documents/Intrahealth/Gofr/updated/gofr/gofr-backend/lib/gofr-backend-site", "routes": { "performance": { "mount": "performance", @@ -19,7 +19,7 @@ } }, "core": { - "path": "/home/ally/gofr/gofr-backend/lib" + "path": "/home/pc/Documents/Intrahealth/Gofr/updated/gofr/gofr-backend/lib" } }, "server": { @@ -88,8 +88,8 @@ "server": { "protocal": "http", "host": "localhost", - "port": "8081", - "basePath": "gofr/fhir", + "port": "8090", + "basePath": "fhir", "username": "", "password": "" }, @@ -163,5 +163,9 @@ "encryption": { "algorithm": "aes-256-ctr", "secret": "b1ea334a-bf5a-11e8-a355-529269fb1459" + }, + "test": { + "DEFAULT_URL": "http://localhost:8090/fhir/DEFAULT", + "PARTITION": "DEFAULT" } } \ No newline at end of file diff --git a/gofr-backend/__tests__/route-config-test.js b/gofr-backend/__tests__/route-config-test.js deleted file mode 100644 index c083f487..00000000 --- a/gofr-backend/__tests__/route-config-test.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict' - -const jest_setup = require('../jest-setup') -jest.mock('axios') - diff --git a/gofr-backend/__tests__/route.auth.test.js b/gofr-backend/__tests__/route.auth.test.js new file mode 100644 index 00000000..1d1f4c75 --- /dev/null +++ b/gofr-backend/__tests__/route.auth.test.js @@ -0,0 +1,119 @@ +'use strict' +const nconf = require('nconf') +const path = require('path') +const configFilePath = path.join(__dirname, "./config/default.json") +nconf.file({file: configFilePath}) + +const testConfig = nconf.get('test') + +const jest_setup = require('../jest-setup') +jest.mock('axios') + +const DEFAULT_URL = testConfig.DEFAULT_URL + +const request = require("supertest") +const route = require("../lib/routes/auth") + +const express = require('express') +const app = express() +app.use(express.urlencoded({extended: false})) +app.use("/", route) + +describe('Test Auth routes', () => { + describe('Test Public User', () => { + test('Test Public User setup', () => { + const MOCK_PUBLIC_USER = { + "resourceType": "Person", "id": "26e19ebd-65e5-4181-84b6-589bcf3bc44b", "meta": { + "versionId": "1", "profile": ["http://gofr.org/fhir/StructureDefinition/gofr-person-user"] + }, "extension": [{ + "url": "http://gofr.org/fhir/StructureDefinition/gofr-owning-organization", "valueReference": { + "reference": "Organization/54cdcbe3-87e0-421f-b657-8313fce5f418" + } + }, { + "url": "http://gofr.org/fhir/StructureDefinition/gofr-password", "extension": [{ + "url": "hash", + "valueString": "6906687939864f1462d52839f52c8800b9ead0aa67d050649a9eed1d9c9ffbe5d815b4d286ee2c2786d1f9781ba72df087b9a2057e8a96c4fc30e870a5cc587b" + }, { + "url": "salt", "valueString": "be664906fbbe50918d8cadb5ebd22093" + }] + }, { + "url": "http://gofr.org/fhir/StructureDefinition/gofr-assign-role", "valueReference": { + "reference": "Basic/gofr-role-public" + } + }], "name": [{ + "text": "GOFR Public User" + }], "telecom": [{ + "system": "email", "value": "public@gofr.org" + }, { + "system": "phone" + }], "active": true + } + require('axios').__setFhirResults(DEFAULT_URL + "/Person/26e19ebd-65e5-4181-84b6-589bcf3bc44b", null, MOCK_PUBLIC_USER) + return request(app).get(`/`).then((response) => { + expect(response.statusCode).toBe(200) + expect(response.body).toEqual({ok: true}) + }) + }) + }) + + describe('Test Local User', () => { + const MOCK_LOCAL_USER_LOOKUP = { + "resourceType": "Bundle", "type": "searchset", "total": 1, "entry": [{ + "furllUrl": DEFAULT_URL + "Person/e9b41c35-7c85-46df-aeea-a4e8dbf0364e", "resource": { + "resourceType": "Person", "id": "e9b41c35-7c85-46df-aeea-a4e8dbf0364e", "meta": { + "versionId": "1", + "lastUpdated": "2023-11-08T10:59:50.435+00:00", + "source": "#fYi1xDSww6QUe05Y", + "profile": ["http://gofr.org/fhir/StructureDefinition/gofr-person-user"] + }, "extension": [{ + "url": "http://gofr.org/fhir/StructureDefinition/gofr-owning-organization", "valueReference": { + "reference": "Organization/54cdcbe3-87e0-421f-b657-8313fce5f418" + } + }, { + "url": "http://gofr.org/fhir/StructureDefinition/gofr-password", "extension": [{ + "url": "hash", + "valueString": "727c00bcb3d604db9b807155240b97347951e5e89e4c69b823279287694501fcaa683d883f5854a05c2c50c5b31413c6bb4a5949876a42b5c5bd74247e5777fc" + }, { + "url": "salt", "valueString": "be664906fbbe50918d8cadb5ebd22093" + }] + }, { + "url": "http://gofr.org/fhir/StructureDefinition/gofr-assign-role", "valueReference": { + "reference": "Basic/gofr-role-admin" + } + }], "name": [{ + "text": "GOFR Admin" + }], "telecom": [{ + "system": "email", "value": "root@gofr.org" + }, { + "system": "phone" + }], "active": true + } + }] + } + + require('axios').__setFhirResults(DEFAULT_URL + "/Person", {telecom: "email|root@gofr.org"}, MOCK_LOCAL_USER_LOOKUP) + test('test local user login', () => { + return request(app).post("/login").send("username=root@gofr.org&password=gofr").then((response) => { + expect(response.statusCode).toBe(200) + expect(response.body.userObj.resource).toEqual(MOCK_LOCAL_USER_LOOKUP.entry[0].resource) + }) + }) + + test('test invalid password', () => { + return request(app).post("/login").send("username=root@gofr.org&password=wrong").then((response) => { + expect(response.statusCode).toBe(401) + }) + }) + + test('test invalid user', () => { + const MOCK_LOCAL_MISSING = { + "resourceType": "Bundle", "type": "searchset", "total": 0, "entry": [] + } + require('axios').__setFhirResults(DEFAULT_URL + "/Person", {telecom: "email|notfound@gofr.org"}, MOCK_LOCAL_MISSING) + return request(app).post("/login").send("username=notfound@gofr.org&password=wrong").then((response) => { + expect(response.statusCode).toBe(401) + }) + + }) + }) +}) diff --git a/gofr-backend/__tests__/route.fhir.test.js b/gofr-backend/__tests__/route.fhir.test.js new file mode 100644 index 00000000..6143b14a --- /dev/null +++ b/gofr-backend/__tests__/route.fhir.test.js @@ -0,0 +1,355 @@ +'use strict' +const nconf = require('nconf') +const path = require('path') +const configFilePath = path.join(__dirname, "./config/default.json") +nconf.file({file: configFilePath}) + +const testConfig = nconf.get('test') +const jest_setup = require('../jest-setup') +jest.mock('axios') + +const DEFAULT_URL = testConfig.DEFAULT_URL +const user = require('../lib/modules/user') + +const PARTITION = testConfig.PARTITION + +const TEST_USER = user.restoreUser({ + resource: {resourceType: "Person"}, permissions: { + "partitions": [{ + "name": "DEFAULT", "*": { + "*": true + } + }, { + "name": "Malawie9b41c35-7c85-46df-aeea-a4e8dbf0364e", "*": { + "*": true + } + }], "special": { + "*": true + }, "read": { + "StructureDefinition": true, "CodeSystem": true, "ValueSet": true, "DocumentReference": { + "constraint": { + "category.exists(coding.exists(code = 'open'))": true + } + } + } + } +}) +const TEST_USER_FAIL = user.restoreUser({ + resource: {resourceType: "Person"}, permissions: {} + +}) +const route = require('../lib/routes/fhir') + + +const express = require('express') +const app = express() +app.use(express.json()) + +const request = require("supertest") +const axios = require('../__mocks__/axios') + +// Set up middleware to add mocks for anything that would exist in the request like session and user from passport +let appUser = TEST_USER +app.use((req, res, next) => { + req.user = appUser + next() +}) + +app.use('/', route) + +describe('TEST /fhir routes', () => { + const MOCK_PERSON = { + resourceType: "Person", id: "test-person", name: [{use: "official", family: "Tester", given: ["Test", "E."]}] + } + const MOCK_PERSON_FAIL = { + resourceType: "Person", id: "test-fail", name: [{use: "official", family: "Tester", given: ["Test", "E."]}] + } + const NOT_FOUND_OUTCOME = { + "resourceType": "OperationOutcome", "issue": [{ + "severity": "error", "code": "exception", "diagnostics": { + "response": "Not found" + } + }] + } + + const NOTLOGGEDIN_OUTCOME = { + resourceType: "OperationOutcome", issue: [{ + severity: "error", code: "forbidden", diagnostics: "Not logged in" + }] + } + const DENIED_OUTCOME = { + resourceType: "OperationOutcome", issue: [{ + severity: "error", code: "forbidden", diagnostics: "Access Denied" + }] + } + + describe('GET /:partition/:resource/:id route', () => { + + it('Should return Not found', () => { + return request(app).get(`/${PARTITION}/StructureDefinition/mock-test`).then((response) => { + expect(response.body).toEqual(NOT_FOUND_OUTCOME) + }) + }) + + it('Should return Not LoggedIn', () => { + appUser = undefined + return request(app).get(`/${PARTITION}/StructureDefinition/mock-test`).then((response) => { + expect(response.statusCode).toBe(401) + expect(response.body).toEqual(NOTLOGGEDIN_OUTCOME) + }) + }) + + it('Should return access denied ', () => { + appUser = TEST_USER_FAIL + return request(app).get(`/${PARTITION}/StructureDefinition/mock-test`).then((response) => { + expect(response.statusCode).toBe(403) + expect(response.body).toEqual(DENIED_OUTCOME) + }) + }) + + it('test read StructureDefinition instance', () => { + const MOCK_PROFILE = { + resourceType: "StructureDefinition", id: "mock-test" + } + appUser = TEST_USER + axios.__setFhirResults(DEFAULT_URL + "/StructureDefinition/mock-test", null, MOCK_PROFILE) + return request(app).get(`/${PARTITION}/StructureDefinition/mock-test`).then((response) => { + expect(response.body).toEqual(MOCK_PROFILE) + }) + }) + + test('test read Location without user', () => { + appUser = null + return request(app).get(`/${PARTITION}/Location/test-practitioner`).then((response) => { + expect(response.statusCode).toBe(401) + expect(response.body).toEqual(NOTLOGGEDIN_OUTCOME) + }) + }) + + test('test read Person without access', () => { + axios.__setFhirResults(DEFAULT_URL + "/Person/test-fail", null, MOCK_PERSON_FAIL) + appUser = TEST_USER_FAIL + return request(app).get(`/${PARTITION}/Person/test-fail`).then((response) => { + expect(response.statusCode).toBe(403) + expect(response.body).toEqual(DENIED_OUTCOME) + }) + }) + }) + + describe('GET /:partition/:resource/:params route', () => { + test('test search CodeSystem', () => { + const MOCK_CODESYSTEM = { + resourceType: "Bundle", id: "mock-test", test: "test", entry: [] + } + axios.__setFhirResults(DEFAULT_URL + "/CodeSystem", {test: "test"}, MOCK_CODESYSTEM) + + appUser = TEST_USER + return request(app).get(`/${PARTITION}/CodeSystem`).query("test=test").then((response) => { + expect(response.statusCode).toBe(200) + expect(response.body).toEqual(MOCK_CODESYSTEM) + }) + }) + test('test search CodeSystem without user', () => { + appUser = null + return request(app).get(`/${PARTITION}/CodeSystem`).query("test=test").then((response) => { + expect(response.statusCode).toBe(401) + expect(response.body).toEqual(NOTLOGGEDIN_OUTCOME) + }) + }) + test('test search Practitioner without access', () => { + appUser = TEST_USER_FAIL + return request(app).get(`/${PARTITION}/Practitioner`).query("test=test").then((response) => { + expect(response.statusCode).toBe(403) + expect(response.body).toEqual(DENIED_OUTCOME) + }) + + }) + }) + + describe('test GET /:partition/ValueSet/id/$expand', () => { + const MOCK_VALUESET_EXPANSION = { + resourceType: "ValueSet", id: "mock-test" + } + + test('test expand ValueSet instance', () => { + axios.__setFhirResults(DEFAULT_URL + "/ValueSet/mock-test/$expand", null, MOCK_VALUESET_EXPANSION) + appUser = TEST_USER + return request(app).get(`/${PARTITION}/ValueSet/mock-test/$expand`).then((response) => { + expect(response.statusCode).toBe(200) + expect(response.body).toEqual(MOCK_VALUESET_EXPANSION) + }) + }) + + test('test expand ValueSet instance without user', () => { + appUser = null + return request(app).get(`/${PARTITION}/ValueSet/mock-test/$expand`).then((response) => { + expect(response.statusCode).toBe(401) + expect(response.body).toEqual(NOTLOGGEDIN_OUTCOME) + }) + }) + + test('test expand ValueSet without access', () => { + appUser = TEST_USER_FAIL + return request(app).get(`/${PARTITION}/ValueSet/mock-fail/$expand`).then((response) => { + expect(response.statusCode).toBe(403) + expect(response.body).toEqual(DENIED_OUTCOME) + }) + }) + + test('test expand ValueSet with field level access', () => { + axios.__setFhirResults(DEFAULT_URL + "/ValueSet/mock-field/$expand", null, MOCK_VALUESET_EXPANSION) + appUser = null + return request(app).get(`/${PARTITION}/ValueSet/mock-field/$expand`).then((response) => { + expect(response.statusCode).toBe(401) + expect(response.body).toEqual(NOTLOGGEDIN_OUTCOME) + }) + }) + }) + + describe('test POST /:partition/:resource route', () => { + test('test create Person', () => { + axios.__setFhirResults(DEFAULT_URL + "/Person", MOCK_PERSON, MOCK_PERSON) + appUser = TEST_USER + return request(app).post(`/${PARTITION}/Person`).send(MOCK_PERSON).then((response) => { + let output = {...MOCK_PERSON} + output.id = "1" + expect(response.statusCode).toBe(201) + expect(response.body).toEqual(output) + }) + }) + test('test create Person without user', () => { + appUser = null + return request(app).post(`/${PARTITION}/Person`).send(MOCK_PERSON).then((response) => { + expect(response.statusCode).toBe(401) + expect(response.body).toEqual(NOTLOGGEDIN_OUTCOME) + }) + }) + test('test create Person without access', () => { + axios.__setFhirResults(DEFAULT_URL + "/Person", MOCK_PERSON_FAIL, MOCK_PERSON_FAIL) + appUser = TEST_USER_FAIL + return request(app).post(`/${PARTITION}/Person`).send(MOCK_PERSON_FAIL).then((response) => { + expect(response.statusCode).toBe(403) + expect(response.body).toEqual(DENIED_OUTCOME) + }) + }) + }) + + describe('test PUT /:partition/:resource/:id', () => { + + test('test update resource: PUT /Person/test-person', () => { + axios.__setFhirResults(DEFAULT_URL + "/Person/test-person", MOCK_PERSON, MOCK_PERSON) + appUser = TEST_USER + return request(app).put(`/${PARTITION}/Person/test-person`).send(MOCK_PERSON).then((response) => { + expect(response.statusCode).toBe(200) + expect(response.body).toEqual(MOCK_PERSON) + }) + }) + + test('test create Person without user', () => { + appUser = null + return request(app).put(`/${PARTITION}/Person/test-person`).send(MOCK_PERSON).then((response) => { + expect(response.statusCode).toBe(401) + expect(response.body).toEqual(NOTLOGGEDIN_OUTCOME) + }) + }) + + test('test create Person without access', () => { + axios.__setFhirResults(DEFAULT_URL + "/Person/test-fail", MOCK_PERSON_FAIL, MOCK_PERSON_FAIL) + appUser = TEST_USER_FAIL + return request(app).put(`/${PARTITION}/Person/test-fail`).send(MOCK_PERSON_FAIL).then((response) => { + expect(response.statusCode).toBe(403) + expect(response.body).toEqual(DENIED_OUTCOME) + }) + }) + }) + + describe('test GET /:partition/DocumentReference/id/$html', () => { + const MOCK_OPEN_DOCUMENT = { + "resourceType": "DocumentReference", + "id": "page-test", + "meta": {"profile": ["http://ihris.org/fhir/StructureDefinition/ihris-document"]}, + "status": "current", + "docStatus": "final", + "date": "2020-06-07T14:54:00Z", + "category": [{ + "coding": [{ + "code": "open", + "system": "http://ihris.org/fhir/CodeSystem/ihris-document-category", + "display": "Open Access" + }] + }], + "content": [{ + "attachment": { + "contentType": "text/markdown", "title": "Testing", "data": "IyBUZXN0aW5nCg==" + } + }] + } + const MOCK_DOCUMENT = {title: "Testing", html: "

Testing

\n
"} + const MOCK_RESTRICTED_DOCUMENT = { + "resourceType": "DocumentReference", + "id": "page-test", + "meta": {"profile": ["http://ihris.org/fhir/StructureDefinition/ihris-document"]}, + "status": "current", + "docStatus": "final", + "date": "2020-06-07T14:54:00Z", + "category": [{ + "coding": [{ + "code": "restricted", + "system": "http://ihris.org/fhir/CodeSystem/ihris-document-category", + "display": "Open Access" + }] + }], + "content": [{ + "attachment": { + "contentType": "text/markdown", "title": "Testing", "data": "IyBUZXN0aW5nCg==" + } + }] + } + + test('test open DocumentReference to HTML instance for open user', () => { + axios.__setFhirResults(DEFAULT_URL + "/DocumentReference/page-test", null, MOCK_OPEN_DOCUMENT) + + appUser = TEST_USER + return request(app).get(`/${PARTITION}/DocumentReference/page-test/$html`).then((response) => { + expect(response.statusCode).toBe(200) + expect(response.body).toEqual(MOCK_DOCUMENT) + }) + }) + + test('test restricted DocumentReference to HTML instance for open user', () => { + axios.__setFhirResults(DEFAULT_URL + "/DocumentReference/page-test", null, MOCK_RESTRICTED_DOCUMENT) + appUser = TEST_USER_FAIL + return request(app).get(`/${PARTITION}/DocumentReference/page-test/$html`).then((response) => { + expect(response.statusCode).toBe(403) + expect(response.body).toEqual(DENIED_OUTCOME) + }) + }) + }) + + describe('test GET /:partition/$short-name', () => { + const MOCK_CODE_LOOKUP = { + "resourceType": "Parameters", "parameter": [{ + "name": "display", "valueString": "Test" + }] + } + const MOCK_STANDARD_RESOURCE = { + "resourceType": "Location", "id": "test", "name": "Test Location" + } + + test('Lookup a codesystem value that exists', () => { + require('axios').__setFhirResults(DEFAULT_URL + "/CodeSystem/$lookup?system=test-system&code=test", null, MOCK_CODE_LOOKUP) + appUser = TEST_USER + return request(app).get(`/${PARTITION}/$short-name?system=test-system&code=test`).then((response) => { + expect(response.body).toEqual({display: "Test"}) + }) + }) + + test('resource standard lookup', () => { + require('axios').__setFhirResults(DEFAULT_URL + "/Location/test", null, MOCK_STANDARD_RESOURCE) + appUser = TEST_USER + return request(app).get(`/${PARTITION}/$short-name?reference=Location/test`).then((response) => { + expect(response.body).toEqual({display: "Test Location"}) + }) + }) + }) +}) diff --git a/gofr-backend/jest.config.js b/gofr-backend/jest.config.js index 482613e6..f1d1ae7d 100644 --- a/gofr-backend/jest.config.js +++ b/gofr-backend/jest.config.js @@ -148,7 +148,8 @@ module.exports = { // "/node_modules/" // ], testPathIgnorePatterns: [ - "resources/" + "resources/", + "__tests__/config/operationOutcomes.js", ], // The regexp pattern or array of patterns that Jest uses to detect test files diff --git a/gofr-backend/lib/routes/fhir.js b/gofr-backend/lib/routes/fhir.js index ddd707fb..75f8ab35 100644 --- a/gofr-backend/lib/routes/fhir.js +++ b/gofr-backend/lib/routes/fhir.js @@ -20,6 +20,9 @@ router.get('/:partition/:resource/:id?', (req, res, next) => { if (req.params.resource.startsWith('$') || (req.params.id && req.params.id.startsWith('$'))) { return next(); } + if ( !req.user ) { + return res.status(401).json( outcomes.NOTLOGGEDIN) + } let allowed = false; if (req.params.id) { allowed = req.user.hasPermissionByName('read', req.params.resource, req.params.id, req.params.partition); @@ -49,7 +52,7 @@ router.get('/:partition/:resource/:id?', (req, res, next) => { /* for custom responses */ logger.error(err.message); const outcome = { ...outcomes.ERROR }; - outcome.issue[0].diagnostics = err.message; + outcome.issue[0].diagnostics = err; return res.status(500).json(outcome); }); } else { @@ -82,13 +85,16 @@ router.get('/:partition/:resource/:id?', (req, res, next) => { }).catch((err) => { logger.error(err.message); const outcome = { ...outcomes.ERROR }; - outcome.issue[0].diagnostics = err.message; + outcome.issue[0].diagnostics = err; return res.status(500).json(outcome); }); } }); router.post('/:partition/:resource', (req, res) => { + if ( !req.user ) { + return res.status(401).json( outcomes.NOTLOGGEDIN) + } const allowed = req.user.hasPermissionByObject('write', req.body, req.params.partition); let resource; if (allowed === true) { @@ -100,7 +106,7 @@ router.post('/:partition/:resource', (req, res) => { } fhirAxios.create(resource, req.params.partition).then((output) => { fhirAudit.create(req.user, req.ip, `${output.resourceType}/${output.id - }${output.meta.versionId ? `/_history/${output.meta.versionId}` : ''}`, true); + }${output?.meta?.versionId ? `/_history/${output.meta.versionId}` : ''}`, true); return res.status(201).json(output); }).catch((err) => { fhirAudit.create(req.user, req.ip, null, false, { resource, err }); @@ -190,6 +196,9 @@ router.patch('/:partition/CodeSystem/:id/:code', (req, res) => { }); router.put('/:partition/:resource/:id', (req, res) => { + if ( !req.user ) { + return res.status(401).json( outcomes.NOTLOGGEDIN) + } const update = req.body; const allowed = req.user.hasPermissionByObject('write', update, req.params.partition); if (!allowed) { @@ -204,7 +213,7 @@ router.put('/:partition/:resource/:id', (req, res) => { } fhirAxios.update(update, req.params.partition).then((resource) => { fhirAudit.update(req.user, req.ip, `${resource.resourceType}/${resource.id - }${resource.meta.versionId ? `/_history/${resource.meta.versionId}` : ''}`, true); + }${resource?.meta?.versionId ? `/_history/${resource.meta.versionId}` : ''}`, true); res.status(200).json(resource); }).catch((err) => { /* return response from FHIR server */ @@ -218,6 +227,9 @@ router.put('/:partition/:resource/:id', (req, res) => { }); router.get('/:partition/ValueSet/:id/\\$expand', (req, res) => { + if ( !req.user ) { + return res.status(401).json( outcomes.NOTLOGGEDIN) + } const allowed = req.user.hasPermissionByName('read', 'ValueSet', req.params.id); if (!allowed) { return res.status(403).json(outcomes.DENIED); @@ -260,6 +272,9 @@ router.get('/:partition/CodeSystem/\\$lookup', (req, res) => { }); router.get('/:partition/DocumentReference/:id/\\$html', (req, res) => { + if ( !req.user ) { + return res.status(401).json( outcomes.NOTLOGGEDIN) + } const allowed = req.user.hasPermissionByName('read', 'DocumentReference', req.params.id, req.params.partition); if (!allowed) { return res.status(403).json(outcomes.DENIED); diff --git a/gofr-backend/lib/routes/passportAuth.js b/gofr-backend/lib/routes/passportAuth.js index 12c1ed48..ce04b13a 100644 --- a/gofr-backend/lib/routes/passportAuth.js +++ b/gofr-backend/lib/routes/passportAuth.js @@ -111,7 +111,7 @@ router.get('/', async (req, res) => { userObj: req.user, }); } - return res.status(200).send(); + return res.status(200).send({ok: true}); }, passport.authenticate('custom-loggedout', {}), (req, res) => { if (req.user) { @@ -134,6 +134,7 @@ router.get('/google/callback', passport.authenticate('google', { failureRedirect router.post('/login', passport.authenticate('local', {}), (req, res) => { res.status(200).json({ + oK: true, userObj: req.user, }); }); diff --git a/gofr-backend/package.json b/gofr-backend/package.json index 4142c99d..9c9846e8 100644 --- a/gofr-backend/package.json +++ b/gofr-backend/package.json @@ -49,6 +49,7 @@ "ihrissmartrequire": "^1.0.1", "is-empty": "^1.2.0", "is-json": "^2.0.1", + "jest": "^29.7.0", "jsdom": "^16.5.3", "json-as-xlsx": "^2.4.2", "json-merger": "^1.1.7",