uask-sys
TypeScript icon, indicating that this package has built-in type declarations

1.2.0 • Public • Published

U-ASK

U-ASK Management System

This repository contains the server and the client of the U-ASK system. Before going further with this setup guide be sure to have been through U-ASK introduction and demo.

The server offers a GraphQL and a REST API. The client allows application to interact with the server by easing authentication and queries.

Authentication is implemented in a separate repository : U-ASK Authentication.

Note: npm scripts needs bash ; please configure git bash as script shell for npm on Windows.

Install the server

git clone https://github.com/u-ask/uask-sys.git

Server configuration

variable description example
APP_ENV the execution environment production
PORT the port to listen to 3000
CALLBACK_ROOT_URL the authorized open id callback URL https://uask.example.com/callback
AUTH_URL the public URL of the authentication service https://uask-api.example.com/oidc
AUTH_JWKS a JSON stringified JWKS {"keys":[{"crv":"P-256",...
SAAS_MODE set to false to remove sign up true
DB_CONNSTR a knex connection string to a PostgreSQL db {"user":"postgres",
host":"localhost",
database":"postgres",
password":"******"}
SENDGRID_API_KEY
SENDGRID_SENDER
a sendgrid authentication key and authorized email address
TWILIO_API_KEY_SID
TWILIO_API_KEY_SECRET
TWILIO_ACCOUNT_SID
a twilio authentication key set

Setting AUTH_JWKS to {} will use a quick start development-only signing set. For more information about JWKS generation, see this example.

SAAS_MODE defaults to true, this will allow anybody to sign up to the system. SAAS mode is required for the first start to allow the first user to sign up. This first user will be able to create more users.

The APP_ENV variable must be set to production. The other possible values are development or demo (see U-ASK).

Sendgrid and / or Twilio account and keys are necessary for sending authentication codes.

Important: do not rely on the .env file in production environment ; set the environment variable at host level. The present guide assumes that this is the case.

Database initialization

npm run migrate

Starting the server

First start, SAAS mode is required to create the first user.

SAAS_MODE=true npm run start

In order to create a first user, run the cli.js script.

./cli.js "https://localhost:<port>" signup

A browser will open on the connexion page. Choose "Sign up" to create a user.

Note: from now, the server can be restarted with SAAS mode disabled. No one will be able to sign up ; new users will be created by an existing user.

Subsequent starts :

npm run start

If no error is logged to the console, the system is properly started. The easiest way to test is to use the U-ASK client.

Install the client

npm i uask-sys

Client usage

This script saves the survey and a sample. The survey is built using U-SAK Domain Model. Note that a survey name must contain a -.

// start.js

import { UaskClient } from "uask-sys/pkce";
import { builder, Sample } from "uask-dom";

const b = builder();

b.survey("First-Survey")
  .pageSet("Questionnaire").pages("Questions");
b.page("Questions")
  .question("Ok?", "__INCLUDED", b.types.yesno)
  .question("When:", "INCLUSION_DATE", b.types.date());

const survey = b.get();

const client = new UaskClient("http://127.0.0.1:3000");
await client.surveyDriver.save(survey);
await client.sampleDriver.save(survey, new Sample("Sample-001"));
await client.destroy();

Run the start.js script ; a browser will open asking to sign in or sign up.

The following script will read the study we have just created :

// check.js

import { UaskClient } from "uask-sys/pkce";

const client = new UaskClient("http://127.0.0.1:3000");
const survey = await client.surveyDriver.getByName("First-Survey");
console.log(survey);
await client.destroy();

This should print a Survey domain model object to the console.

Persistence identifiers

When a domain model object is saved into the persistent store, it is given some identifiers. For example a Participant has a unique code that is computed server side. Changes done server side are returned by the client and should be used to create an updated version of the saved domain model object.

import { UaskClient } from "uask-sys/pkce";
import { ParticipantBuilder } from "uask-dom";

const client = new UaskClient("http://127.0.0.1:3000");

const survey = await client.surveyDriver.getByName("First-Survey");
const sample = await client.sampleDriver.getBySampleCode(survey, "Sample-001");
const participant = new ParticipantBuilder(survey, "", sample).build();

const keys = await client.participantDriver.save(survey, participant);
const participantWithCode = participant.update(keys);
console.log(participantWithCode);
await client.destroy();

This prints a Participant domain model object to the console with a participantCode computed server side.

Saving a participant and its interviews :

import { UaskClient } from "uask-sys/pkce";
import { ParticipantBuilder } from "uask-dom";

const client = new UaskClient("http://127.0.0.1:3000");

const survey = await client.surveyDriver.getByName("First-Survey");
const sample = await client.sampleDriver.getBySampleCode(survey, "Sample-001");

const builder0 = new ParticipantBuilder(survey, "", sample);
builder0.interview("Questionnaire")
  .item("__INCLUDED").value(true)
  .item("INCLUSION_DATE").value(new Date());
const participant = builder0.build();
const interview = participant.interviews[0];

const participantKeys = await client.participantDriver.save(survey, participant);
const participantWithCode = participant.update(participantKeys);

const interviewKeys = await client.interviewDriver.save(survey, participantWithCode, interview);
const interviewWithNonce = interview.update(interviewKeys);
const builder1 = new ParticipantBuilder(survey, participantWithCode);
builder1.interview(interviewWithNonce);

const persistedParticipant = builder1.build();
console.log(persistedParticipant);
await client.destroy();

This prints a Participant domain model object to the console with a participantCode computed server side. The Interview contained in the Participant has a nonce property also computed server side.

Audit trail

All modification are tracked into the audit trail. The following snippet modify the patient created above and display all journalized modifications.

import { UaskClient } from "uask-sys/pkce";
import { ParticipantBuilder } from "uask-dom";

const client = new UaskClient("http://127.0.0.1:3000");

const survey = await client.surveyDriver.getByName("First-Survey");
const samples = await client.sampleDriver.getAll(survey, "Sample-001");
const participant = await client.participantDriver.getByParticipantCode(survey, samples, "000002")
const interview = participant.interviews[0];

const builder = new ParticipantBuilder(survey, participant);
builder.interview("Questionnaire", interview.nonce)
  .item("__INCLUDED").value(false)
  .item("INCLUSION_DATE").value(new Date());
const updatedParticipant = builder.build();

await client.participantDriver.save(survey, updatedParticipant);
const records = await client.auditDriver.get(survey, {participantCode: "000002"})

console.log(records);
await client.destroy();

The second argument of auditDriver.get(survey, {participantCode: "000002"}) may take additional information to narrow the audit target. See auditDriver reference

generateDSL

The generateDSL function takes a Survey ans returns a string that contains the code used to build the survey using DSL builders as defined in U-ASK Domain Model.

import { UaskClient, generateDSL } from "uask-sys/pkce";

const client = new UaskClient("http://127.0.0.1:3000");

const survey = await client.surveyDriver.getByName("First-Survey");
const dsl = generateDSL(survey);
console.log(dsl);

The snippet above regenerates the code used to build the example used in this guide, see Client usage above.

Client reference

For more information on the domain object model, see U-ASK Domain Model.

UaskClient.surveyDriver

method returns description
getByName(name: string) Promise<Survey> get a survey by its name
save(survey: Survey) Promise save a survey and all its components

UaskClient.sampleDriver

method returns description
getAll(survey: Survey) Promise<Sample[]> get all samples for given survey
getBySampleCode(survey: Survey, code: string) Promise<Sample> get a sample given its code
save(survey: Survey, sample: Sample) Promise save a sample for the given survey

UaskClient.participantDriver

method returns description
getAll(survey: Survey) Promise<Participant[]> get all participants for given survey
getBySample(survey: Survey, sample: Sample) Promise<Participant[]> get all participants for given sample
getByParticipantCode(survey: Survey, code: string) Promise<Participant> get a participant given its code
save(survey: Survey, participant: Participant) Promise save a participant
delete(survey: Survey, participant: Participant) Promise delete a participant

UaskClient.interviewDriver

method returns description
save(survey: Survey, participant: Participant, interview: Interview) Promise save an interview
delete(survey: Survey, participant: Participant, interview: Interview) Promise delete an interview

UaskClient.participantDriver

method returns description
getAll(survey: Survey, sample?: Sample) Promise<ISummary[]> get lightweight summaries for participants

UaskClient.userDriver

method returns description
getAll(survey: Survey) Promise<User[]> get all users for given survey
getByUserId(survey: Survey, userid: string) Promise<User> get a user given its userid
save(survey: Survey, user: User) Promise save a user for the given survey

UaskClient.auditDriver

method returns description
get(survey: Survey, ref: AuditableRef) Promise<AuditRecord[]> get audit records

AuditableRef

property description
patientCode participant code
nonce? interview nonce
variableName? item variable name
intance? instance

Survey development life cycle

With U-ASK the recommended way to build surveys is to use DSL directly. It is recommended to create a new project with npm init, the add U-ASK dependencies:

npm install uask-dom uask-sys

Initialize a new survey with name Second-Survey on server https://uask-api.example.com:

./node_modules/.bin/uask-cli "https://uask-api.example.com" init "Second-Survey" > second-survey.js

This will create a starter script that creates a minimal survey.

In order to create the survey on the server, run the script :

node ./second-survey.js

The code may also be generated from an existing survey, by replacing the operation name from init to generate or gen:

./node_modules/.bin/uask-cli "https://uask-api.example.com" gen "Second-Survey" > second-survey.js

Survey code should be maintained in a software version control system like Github.

Readme

Keywords

none

Package Sidebar

Install

npm i uask-sys

Weekly Downloads

2

Version

1.2.0

License

MIT

Unpacked Size

1.35 MB

Total Files

81

Last publish

Collaborators

  • ydarma