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",