Last updated: June 16, 2022
reports
is Django project for compiling dynamic reports using R Markdown and
KoBoToolbox. It is built on the R package knitr: http://yihui.name/knitr/.
This code currently runs on https://data.equitytool.org and relies on https://kf.kobotoolbox.org for authentication, form deployment, and submission collection/storage.
To create an administrative report that lists all the users and projects stored in the database:
- Log into https://data.equitytool.org/admin/ as a superuser;
- Click "+ Add" next to "Admin stats report tasks";
- Click "SAVE";
- A screen listing "new report" first as well as previous reports below will appear;
- Refresh this page every few minutes until "new report" changes into "complete report";
- Once that happens, click "complete report";
- Finally, click "equitytool_admin_stats....zip" (to the right of "Result") to download the ZIP file containing the statistics.
An administrator-defined form that regular users can select when they create
new projects. The form is then sent to the regular user's linked KoBoToolbox
account, creating a new project that, in turn, is referenced by a
reporter.Rendering
These R Markdown templates transform collected data from its raw state into formatted reports (narrative, tables, charts). They are available read-only to all users, but may only be changed by superusers via the https://data.equitytool.org/admin/ (Django Admin) interface.
Connects the R Markdown reporter.Template
s to data collected with
KoBoToolbox. There is one instance of this for each user-created project.
This application uses a special
interface
of kf.kobotoolbox.org to create KoBoToolbox users without email confirmation.
Once a user registers in this way, they are then authenticated by sending their
credentials over HTTPS to the KoBoToolbox server (see
reporter.KoboApiAuthBackend
). If the credentials are correct, KoBoToolbox
returns an API key, which this application then stores in
reporter.UserExternalApiToken
. That key then authenticates subsequent
requests to deploy forms and retrieve submissions.
There are also local-only users whose passwords (hashed) are stored directly in this application's database. Superusers are an example of this. These users have privileges to administer this application but not the connected KoBoToolbox instance. Local-only users also cannot create data collection projects as they have no access to KoBoToolbox.
This model allows administrative reports to be generated in the background where they are not subject to the same time limits as ordinary web application requests.
Mustache tags are supported so we can return a warning message if a
deployment has fewer than 150 responses. See
reporter.tests.TestRendering.test_warning
.
rendering__name
:Rendering.name
, i.e. the user's name for the projectform__name
:Form.name
, e.g.Tajikistan (DHS 2012)
request__show_urban
: the value of?show_urban=
in the URL used to request the report
- Tables in DOCX exports do not appear properly in LibreOffice: see jgm/pandoc#515
Production installation with Dokku
For this example, we're using an AWS t3.small EC2 instance, which provides 2 GiB of RAM, along with a 40 GiB EBS root volume. It is running Ubuntu 20.04.
- Due to the limited amount of RAM, add a 5 GiB swap file:
Add the following to
sudo fallocate --length 5G /swapfile sudo mkswap /swapfile sudo chmod 600 /swapfile
/etc/fstab
to enable swap at each boot:Enable the swap now:/swapfile none swap sw 0 0
sudo swapon -a
- Install Dokku:
wget https://raw.githubusercontent.com/dokku/dokku/v0.24.7/bootstrap.sh sudo DOKKU_TAG=v0.24.7 bash bootstrap.sh sudo reboot
- Create the Dokku application:
dokku apps:create data.equitytool.org
- Configure the new application:
Connect the application to an instance of KoBoToolbox; see Development without Dokku for more information:
dokku config:set data.equitytool.org ALLOWED_HOSTS='data.equitytool.org' dokku config:set data.equitytool.org SECRET_KEY='[your randomly-generated Django secret key]' # Optional Python exception logging dokku config:set data.equitytool.org RAVEN_DSN='[your Sentry DSN]'
dokku config:set data.equitytool.org KPI_URL='https://kf.kobotoolbox.org' dokku config:set data.equitytool.org KPI_API_KEY='[your kpi authorized application key]'
- Enable TLS (HTTPS):
dokku letsencrypt:enable data.equitytool.org
- Enable automatic renewal of TLS certificates:
dokku letsencrypt:cron-job --add
- Install Postgres and link it with the new application:
sudo dokku plugin:install https://github.com/dokku/dokku-postgres.git dokku postgres:create reports dokku postgres:link reports data.equitytool.org
- Add persistent storage for media uploads:
dokku storage:mount data.equitytool.org /var/lib/dokku/data/storage/data.equitytool.org:/app/media
- Follow the Dokku
documentation
to deploy the application code from your local machine to this new server
using
git push
. This relies on the base image having already been built and pushed to Docker Hub by GitHub Actions. You must make a new release (or push a new tag) to trigger building of the base image. Reducing the size of this base image (currently over 4 GiB) would be a nice improvement.
- Make sure the
master
branch on GitHub has been updated with the code you want to deploy. - Create a new release (or
push a new tag) from the tip of
master
to trigger building of the base image by GitHub Actions. - Wait for the build to complete. Verify that the base image for your new release is present on Docker Hub.
- Make sure your public SSH key has been added to
authorized_keys
on the production server. - Use
dokku ssh-keys:list
to verify that your SSH key is added to dokku.- If the SSH key needs to be added, copy the
.pub
file on to the server and rundokku ssh-keys:add <keyname> <path/to/key>
- If the SSH key needs to be added, copy the
- Create a new Git remote in your local copy of this repository, unless
you've already set this up:
git remote add PRODUCTION dokku@data.equitytool.org:data.equitytool.org
- Make sure the
master
branch in your local repository has been updated with the code you want to deploy. - Deploy by pushing to the
PRODUCTION
remote:git push PRODUCTION master
- Once you're satisfied with the deployment, you may want to prune unused
Docker resources to save disk space:
docker system prune -a
This application requires a working instance of KoBoToolbox to run. See kobo-install for instructions on how to install such an instance.
- Go to
https://[YOUR KPI DOMAIN]/admin/kpi/authorizedapplication/
(you will need to log in as a superuser); - Click
Add authorized application
; - Name your application and note the randomly-generated key (or enter your
own);
- NB: To escape a
$
in the key, double it to$$
.
- NB: To escape a
- Click
Save
; - Edit
docker-compose.yml
for thisreports
application:- Set the
KPI_API_KEY
environment variable equal to the application key generated above; - Set
KPI_URL
tohttps://[YOUR KPI DOMAIN]/
;- If you are using a locally-hosted KoBoToolbox instance, you may need
to configure
extra_hosts
as well.
- If you are using a locally-hosted KoBoToolbox instance, you may need
to configure
- Set
ALLOWED_HOSTS
to match the hostname of yourreports
instance; see https://docs.djangoproject.com/en/3.2/ref/settings/#allowed-hosts.
- Set the
- Execute
docker compose pull
; - Execute
docker build -t kobotoolbox/reports_base -f Dockerfile.base .
(this is a slow process); - Execute
docker compose build
;- WARNING: This builds a Docker image using the latest front-end code in
your source tree, BUT the static files and Node dependencies built
into the Docker image will be shadowed by the
./:/app
volume indocker-compose.yml
. You must runnpm install
andnpm run build
(ornpm run dev
) additionally, or else the application will run with stale code.
- WARNING: This builds a Docker image using the latest front-end code in
your source tree, BUT the static files and Node dependencies built
into the Docker image will be shadowed by the
- Execute
docker compose up -d postgres
; - Execute
docker compose logs -f
; - Wait for the Postgres container to settle as indicated by the logs;
- Interrupt (CTRL+C)
docker compose logs
; - Start the web application with
docker compose up -d
; - Get a shell inside the application container by running
docker compose exec koboreports bash
; - If desired, load some sample
Form
s into the database:# Inside the application container source activate koboreports ./manage.py loaddata dev/sample-forms.json
- To access the Django Admin interface, you'll need a superuser account.
Create one now:
# Inside the application container source activate koboreports ./manage.py createsuperuser
- Build the front-end files:
- On your host computer (not inside a Docker container), enter the
jsapp
directory within your source tree;- (Your source tree is mounted inside the Docker container by the
./:/app
volume indocker-compose.yml
)
- (Your source tree is mounted inside the Docker container by the
- Use nvm or similar to run the same
version of Node as specified in
Dockerfile.base
; - Execute
npm install
; - If you plan to do front-end development, execute
npm run dev
, which will watch your code for changes and reload as needed.- If you do this, you must visit the application at http://localhost:8080/. Accessing port 5000 will use stale front-end code.
- If you do not plan to touch front-end code, execute
npm run build
to rebuild the front-end static files one time only. You must do this at least once after switching branches or changing front-end dependencies, even if you do not edit any front-end code yourself.
- On your host computer (not inside a Docker container), enter the
- Access the application in a browser:
- If you are not working on front-end code and have used only
npm run build
, access the application at http://localhost:5000/. - If you are modifying front-end code and executed
npm run dev
, you must access the application at http://localhost:8080/. Port 5000 will appear to work, but it will serve stale front-end code.
- If you are not working on front-end code and have used only