12.2. The CamCOPS server configuration file

CamCOPS needs a configuration file. Under Linux, this is normally something that you create at /etc/camcops/camcops.conf, from a template produced by CamCOPS. It is the configuration file that points to your database.

12.2.1. Databases and configuration files

In general, it is best to have a single CamCOPS database and a single CamCOPS configuration file. This is simple. You can add groups dynamically, and use group security to manage data access. Groups can be entirely isolated from each other, which mimics having multiple databases, but they can also overlap in useful ways.

It’s also possible, of course, to have multiple CamCOPS databases, each with its own configuration file.

If you do operate with multiple databases/configuration files, you may want to use the camcops_server_meta tool, which allows you to run the same camcops_server command over multiple configuration files in one go (for example, to upgrade the databases for a new version of CamCOPS).

12.2.2. Format of the configuration file

  • The config file is in standard INI file format.

  • UTF-8 encoding. Use this! The file is explicitly opened in UTF-8 mode.

  • Comments. Hashes (#) and semicolons (;) denote comments.

  • Sections. Sections are indicated with: [section]

  • Name/value (key/value) pairs. The parser used is ConfigParser. It allows name=value or name:value.

  • Avoid indentation of parameters. (Indentation is used to indicate the continuation of previous parameters.)

  • Parameter types, referred to below, are:

    • String. Single-line strings are simple.

    • Multiline string. Here, a series of lines is read and split into a list of strings (one for each line). You should indent all lines except the first beyond the level of the parameter name, and then they will be treated as one parameter value.

    • Integer. Simple.

    • Boolean. For Boolean options, true values are any of: 1, yes, true, on (case-insensitive). False values are any of: 0, no, false, off.

    • Loglevel. Possible log levels are (case-insensitive): debug, info, warning `` (equivalent: ``warn), error, and critical (equivalent: fatal).

    • Date. Dates are in the format YYYY-MM-DD, e.g. 2013-12-31, or blank for “no date”.

    • Date/time. Date/time values are in the format YYYY-MM-DDTHH:MM or other ISO 8601-compatible syntax, e.g. 2013-12-31T09:00, or blank for “no date/time”.

12.2.3. Note regarding Docker

If you are using CamCOPS with Docker, see The CamCOPS configuration file for Docker as there are a few special requirements. Relevant sections are also marked below.

12.2.4. Config file sections

  • The main CamCOPS site settings are in [site].

  • Options for configuring the web server aspects are in [server].

  • A list of export recipients is in the [recipients] section.

  • Each export recipient is defined in a section named [recipient:RECIPIENT_NAME] where RECIPIENT_NAME is the user-defined name of that recipient.

12.2.5. Options for the “[site]” section

12.2.5.1. Database connection

12.2.5.1.1. DB_URL

String.

The SQLAlchemy connection URL for the CamCOPS database. See https://docs.sqlalchemy.org/en/latest/core/engines.html. Examples:

  • MySQL under Linux via mysqlclient:

    $ pip install mysqlclient
    
    DB_URL = mysql+mysqldb://<username>:<password>@<host>:<port>/<database>?charset=utf8
    

    (The default MySQL port is 3306, and ‘localhost’ is often the right host.)

  • MySQL under Linux via pymysql:

    $ pip install pymysql
    
    DB_URL = mysql+pymysql://<username>:<password>@<host>:<port>/<database>?charset=utf8
    
  • SQL Server under Windows via ODBC and username/password authentication.

    C:\> pip install pyodbc
    
    DB_URL = mssql+pyodbc://<username>:<password>@<odbc_dsn_name>
    
  • … or via Windows authentication:

    DB_URL = mssql+pyodbc://@<odbc_dsn_name>
    

For our notes on database drivers for a different software package, see https://crateanon.readthedocs.io/en/latest/installation/database_drivers.html.

Note

If you are using CamCOPS via Docker, see here.

12.2.5.1.2. DB_ECHO

Boolean.

Echo all SQL?

12.2.5.2. URLs and paths

12.2.5.2.1. LOCAL_INSTITUTION_URL

String.

Clicking on your institution’s logo in the CamCOPS menu will take you to this URL. Edit this to point to your institution.

12.2.5.2.2. LOCAL_LOGO_FILE_ABSOLUTE

String.

Specify the full path to your institution’s logo file, e.g. /var/www/logo_local_myinstitution.png. It’s used for PDF generation; HTML views use the fixed string static/logo_local.png, aliased to your file via the Apache configuration file). Edit this setting to point to your local institution’s logo file.

Note

If you are using CamCOPS via Docker, see here.

Your logo will be scaled to 45% of the active page width. You may need to add blank space to the left if it looks funny. See picture below.

../_images/scaling_logos.png

12.2.5.2.3. CAMCOPS_LOGO_FILE_ABSOLUTE

String.

As for LOCAL_LOGO_FILE_ABSOLUTE, but for the CamCOPS logo. It’s fine not to specify this; a default will be used.

Note

If you are using CamCOPS via Docker, see here.

12.2.5.2.4. EXTRA_STRING_FILES

Multiline string.

A multiline list of filenames (with absolute paths), read by the server, and used as EXTRA STRING FILES. Should as a minimum point to the string file camcops.xml. May use “glob” pattern-matching (see https://docs.python.org/3.5/library/glob.html).

Note

If you are using CamCOPS via Docker, see here.

12.2.5.2.5. RESTRICTED_TASKS

Multiline string.

This option allows you to have restricted task content on your server, and to permit tasks only to specific groups (typically, the ones that have paid for a licence).

We don’t want to do anything to inhibit the uploading of data. Therefore, this option restricts the provision, by the server to the clients, of task strings for restricted tasks (i.e. a client cannot download strings from a restricted task unless they are a member of an authorized group).

Each line is in the format:

<xml_task_name>: <groupname>, <groupname>, ...

That is, an XML task name is mapped to a comma-separated list of group names. These groups are the AUTHORIZED groups; any group that does not appear is not authorized. (If a blank list is specified, no groups are authorized! That would be a bit odd; why not just remove it from EXTRA_STRING_FILES?)

If a task’s name is not in this list, the task is not restricted.

The XML task name is usually, but not always, the same as the task’s table name. See C++ tasks that implement xstringTaskname(), or equivalently Python tasks that implement extrastring_taskname, for examples that deviate from this general rule.

12.2.5.2.6. LANGUAGE

String. Default: en_GB.

This setting determines the language in which the server operates for users who have not set a language preference, or who are not logged in. This language also applies to “back-end” work, like exporting tasks.

The language code is in the format en_GB (two-letter language code, underscore, two- or three-letter country code).

If the language is not recognized, a warning is given and the server switches to its default.

12.2.5.2.7. SNOMED_TASK_XML_FILENAME

String.

Filename of special XML file containing SNOMED CT codes used by CamCOPS tasks. This file is OK to use in the UK, but not necessarily elsewhere. See SNOMED CT.

Note

If you are using CamCOPS via Docker, see here.

12.2.5.2.8. SNOMED_ICD9_XML_FILENAME

String.

Name of XML file mapping ICD-9-CM codes to SNOMED-CT.

Created by camcops_server convert_athena_icd_snomed_to_xml; see SNOMED CT.

Note

If you are using CamCOPS via Docker, see here.

12.2.5.2.9. SNOMED_ICD10_XML_FILENAME

String.

Name of XML file mapping ICD-10[-CM] codes to SNOMED-CT.

Created by camcops_server convert_athena_icd_snomed_to_xml; see SNOMED CT.

Note

If you are using CamCOPS via Docker, see here.

12.2.5.2.10. WKHTMLTOPDF_FILENAME

String.

For the pdfkit PDF engine, specify a filename for wkhtmltopdf (https://wkhtmltopdf.org/) that incorporates any need for an X Server (not the default /usr/bin/wkhtmltopdf). See http://stackoverflow.com/questions/9604625/ . A suitable one is bundled with CamCOPS, so you shouldn’t have to alter this default. A blank parameter here usually ends up calling /usr/bin/wkhtmltopdf

12.2.5.3. Server geographical location

12.2.5.3.1. REGION_CODE

String. Default: GB.

ISO 3166-1 alpha-2 region code. Currently used for parsing telephone numbers.

12.2.5.4. Login and session configuration

12.2.5.4.2. SESSION_TIMEOUT_MINUTES

Integer. Default: 30.

Time (in minutes) after which a session will expire.

12.2.5.4.3. SESSION_CHECK_USER_IP

Boolean. Default: true.

If true: CamCOPS checks the user’s IP address on every request, and prohibits the user from changing IP address within a session. (A change of IP address will require them to log in again.) If False, the IP address is not checked and is permitted to change.

Setting this to True is more conservative as a security setting, but can cause problems if user IP addresses (as seen by the CamCOPS server) change due to e.g. a load balancer, or the user switching networks. Set it to False if users are being logged out before SESSION_TIMEOUT_MINUTES is reached.

12.2.5.4.4. PASSWORD_CHANGE_FREQUENCY_DAYS

Integer.

Force password changes (at webview login) with this frequency (0 for never). Note that password expiry will not prevent uploads from tablets, but when the user next logs on, a password change will be forced before they can do anything else.

12.2.5.4.5. LOCKOUT_THRESHOLD

Integer. Default: 10.

Lock user accounts after every n login failures.

12.2.5.4.6. LOCKOUT_DURATION_INCREMENT_MINUTES

Integer. Default: 10.

Account lockout time increment.

Suppose LOCKOUT_THRESHOLD = 10 and LOCKOUT_DURATION_INCREMENT_MINUTES = 20. Then:

  • After the first 10 failures, the account will be locked for 20 minutes.

  • After the next 10 failures, the account will be locked for 40 minutes.

  • After the next 10 failures, the account will be locked for 60 minutes, and so on. Time and administrators can unlock accounts.

12.2.5.4.7. DISABLE_PASSWORD_AUTOCOMPLETE

Boolean. Default: true.

If set to true, asks browsers not to autocomplete the password field on the main login page. The correct setting for maximum security is debated (don’t cache passwords, versus allow a password manager so that users can use better/unique passwords). Note that some browsers (e.g. Chrome v34 and up) may ignore this.

12.2.5.4.8. MFA_METHODS

Multiline string.

A multiline list of enabled multi-factor authentication (MFA) methods. Users can choose from the options that you enable here.

The possible values are:

  • totp: Use an app such as Google Authenticator or Twilio Authy.

  • hotp_email: Send a code by email.

  • hotp_sms: Send a code by SMS (text message). For this option, you must also configure SMS_BACKEND.

  • no_mfa: permit login with no MFA (i.e. just with a username/password combination).

To enforce multi-factor authentication on the server, do not include no_mfa in this list (but include at least one other). If you don’t specify anything, only no_mfa is used.

Open MFA standards are defined in RFC 4226 (HOTP: An HMAC-Based One-Time Password Algorithm) and in RFC 6238 (TOTP: Time-Based One-Time Password Algorithm).

12.2.5.4.9. MFA_TIMEOUT_S

Integer. Default: 600.

Seconds the user has to enter their six-digit code during multi-factor authentication. Zero means never time out.

12.2.5.5. Suggested filenames for saving PDFs from the web view

Try these with Chrome, Firefox. Internet Explorer may be less obliging.

12.2.5.5.1. PATIENT_SPEC_IF_ANONYMOUS

String.

For anonymous tasks, this fixed string is used as the patient descriptor (see also PATIENT_SPEC below). Typically “anonymous”.

12.2.5.5.2. PATIENT_SPEC

String.

A string, into which substitutions will be made, that defines the patient element available for substitution into the *_FILENAME_SPEC variables (see below). Possible substitutions:

surname

Patient’s surname in upper case

forename

Patient’s forename in upper case

dob

Patient’s date of birth (format %Y-%m-%d, e.g. 2013-07-24)

sex

Patient’s sex (F, M, X)

idshortdesc1, idshortdesc2, …

Short description of the relevant ID number, if that ID number is not blank; otherwise blank

idnum1, idnum2, …

Actual patient ID numbers

allidnums

All available ID numbers in “shortdesc-value” pairs joined by _. For example, if ID numbers 1, 4, and 5 are non-blank, this would have the format <idshortdesc1>-<idnum1>_<idshortdesc4>-<idnum4>_ <idshortdesc5>-<idnum5>

Use braces for substituted variables, e.g. {forename}_{surname}.

12.2.5.5.3. TASK_FILENAME_SPEC

String.

Filename specification used for task downloads (e.g. PDFs).

Substitutions will be made to determine the filename to be used for each file. Possible substitutions:

patient

Patient string. If the task is anonymous, this is the config variable PATIENT_SPEC_IF_ANONYMOUS; otherwise, it is defined by PATIENT_SPEC above.

created

Date/time of task creation. Dates/times are in the format %Y-%m-%dT%H%M, e.g. 2013-07-24T2004. They are expressed in the timezone of creation (but without the timezone information for filename brevity).

now

Time of access/download (i.e. time now), in local timezone.

tasktype

Base table name of the task (e.g. “phq9”). May contain an underscore. Blank for trackers/CTVs.

serverpk

Server’s primary key. (In combination with tasktype, this uniquely identifies not just a task but a version of that task.) Blank for trackers/CTVs.

filetype

e.g. pdf, html, xml (lower case)

anonymous

Evaluates to the config variable PATIENT_SPEC_IF_ANONYMOUS if anonymous, otherwise to a blank string

… plus all those substitutions applicable to PATIENT_SPEC.

Use braces for substituted variables, e.g. {patient}_{created}.

After these substitutions have been made, the entire filename is then processed to ensure that only characters generally acceptable to filenames are used (see camcops_server.cc_modules.cc_filename.convert_string_for_filename() in the CamCOPS source code). Specifically:

  • Unicode is converted to 7-bit ASCII (will mangle, e.g. removing accents)

  • spaces are converted to underscores

  • characters are removed unless they are one of the following:

    • all alphanumeric characters (0-9, A-Z, a-z);

    • -, _, ., and the operating-system-specific directory separator (Python’s os.sep, a forward slash / on UNIX or a backslash \ under Windows).

12.2.5.5.4. TRACKER_FILENAME_SPEC

String.

Filename specification used for tracker downloads; see TASK_FILENAME_SPEC.

12.2.5.5.5. CTV_FILENAME_SPEC

String.

Filename specification used for clinical text view downloads; see TASK_FILENAME_SPEC.

12.2.5.6. Email options

These options control the sending of e-mails by the CamCOPS server.

12.2.5.6.1. EMAIL_HOST

String.

Hostname of e-mail (SMTP) server.

12.2.5.6.2. EMAIL_PORT

Integer. Default: 587.

Port number of e-mail (SMTP) server. The standard SMTP port is 25, but 587 is the default for using TLS, which is more secure (see below).

12.2.5.6.3. EMAIL_USE_TLS

Boolean. Default: true.

Use a TLS (secure) connection to talk to the SMTP server? The default is true; turn this off for an insecure connection.

This is used for explicit TLS connections, usually on port 587 (in which the connection is opened and then a STARTTLS command is issued).

12.2.5.6.4. EMAIL_HOST_USERNAME

String.

Username on e-mail server. (Surprisingly, some e-mail servers allow this to be blank. Be wary of them!)

12.2.5.6.5. EMAIL_HOST_PASSWORD

String.

Password on e-mail server. (Not stored in database.)

12.2.5.6.6. EMAIL_FROM

String.

“From:” address used in e-mails. See RFC 5322. Only one is permitted here.

12.2.5.6.7. EMAIL_SENDER

“Sender:” address used in e-mails. See RFC 5322. Only one is permitted.

12.2.5.6.8. EMAIL_REPLY_TO

String.

“Reply-To:” address used in e-mails. See RFC 5322.

12.2.5.7. SMS options

12.2.5.7.1. SMS_BACKEND

String. Default: console.

Back-end service to send SMS (text) messages as part of multi-factor authentication (see MFA_METHODS).

Options are:

  • kapow

  • twilio

  • console

The console option is only for testing; it prints the SMS to the server’s console log, but does nothing useful.

Supported backends are Kapow and Twilio SMS. A paid account is needed for these services, which are then configured as follows:

[sms_backend:kapow]

USERNAME =
PASSWORD =


[sms_backend:twilio]

SID =
TOKEN =
FROM_PHONE_NUMBER =

12.2.5.8. User download options

12.2.5.8.1. PERMIT_IMMEDIATE_DOWNLOADS

Boolean. Default: false.

Should the system allow users to use the front end web service to create and download files? This might be convenient, but a disadvantage is that if the file to be downloaded is large, it will take a long time. Also if you close your web browser or lose your internet connection, the download will be lost. A further disadvantage is that it “ties up” one web front end process in creating the download (whereas creating file for later download, as below, uses a pool of back-end worker processes and does not; this may have some performance implications for your web site).

12.2.5.8.2. USER_DOWNLOAD_DIR

String. Default: none.

Root directory for storing temporary user downloads (when the user asks for files to be created for later download). Within this, a directory will be created for every user as required (whose name is the user’s ID number).

If this is not set, queued downloads are not offered.

12.2.5.8.3. USER_DOWNLOAD_FILE_LIFETIME_MIN

Integer. Default: 60.

When users create files on the server for later download, how long should these files “live” before being deleted?

12.2.5.8.4. USER_DOWNLOAD_MAX_SPACE_MB

Integer. Default: 100.

Maximum amount of space that each user is permitted to use for short-term download storage on the server.

If this is zero, queued downloads are not offered.

12.2.5.9. Debugging options

12.2.5.9.1. WEBVIEW_LOGLEVEL

Loglevel. Default: info.

Set the level of detail provided from the webview to stderr (e.g. to the Apache server log).

Note that for “debug”-level information to show up, you must also provide the --verbose argument to camcops_server.

12.2.5.9.2. CLIENT_API_LOGLEVEL

Loglevel. Default: info.

Set the log level for the tablet client database access script.

Note that for “debug”-level information to show up, you must also provide the --verbose argument to camcops_server.

12.2.5.9.3. ALLOW_INSECURE_COOKIES

Boolean.

DANGEROUS option that removes the requirement that cookies be HTTPS (SSL) only.

12.2.6. Options for the “[server]” section

12.2.6.1. Common web server options

CamCOPS incorporates a Python web server. You can choose which one to launch:

  • CherryPy: a “proper” one; multithreaded; works on Windows and Linux.

  • Gunicorn: a “proper” one; multiprocess; Linux/UNIX only.

  • Pyramid: a “toy” one for debugging. (CamCOPS is written using Pyramid as its web framework; Pyramid is excellent, but other software is generally better for use as the web server.)

You may also want to configure a CamCOPS server behind a “front-end” web server such as Apache. Further options to help with this are described below.

12.2.6.1.1. HOST

String. Default: 127.0.0.1.

TCP/IP hostname to listen on. (See also UNIX_DOMAIN_SOCKET.)

Note some variations. For example, if your machine has an IP (v4) address of 192.168.1.1, then under Linux you will find the following:

  • Using 192.168.1.1 will make the CamCOPS web server directly visible to the network.

  • Using 127.0.0.1 will make it invisible to the network and visible only to other processes on the same computer.

  • Using localhost will trigger a lookup from localhost to an IP address, typically 127.0.0.1.

Note

If you are using CamCOPS via Docker, see here.

12.2.6.1.2. PORT

Integer. Default: 8000.

TCP port number to listen on. (See also UNIX_DOMAIN_SOCKET.)

Note

If you are using CamCOPS via Docker, see here.

12.2.6.1.3. UNIX_DOMAIN_SOCKET

String. Default: none.

Filename of a UNIX domain socket (UDS) to listen on (rather than using TCP/IP). UDS is typically faster than TCP (see e.g. https://stackoverflow.com/questions/14973942/tcp-loopback-connection-vs-unix-domain-socket-performance). If specified, this overrides the TCP options, HOST and PORT.

For example, /run/camcops/camcops.socket (as per the Filesystem Hierarchy Standard).

(Not applicable to the Pyramid test web server; CherryPy/Gunicorn only.)

Note

The socket “file” is a pseudo-file that is created by CamCOPS during operation, and vanishes when CamCOPS stops. You don’t have to create it – but you need to ensure that CamCOPS can write to the directory where it lives. If you look at the file with ls -l, you will see this:

srwxrwxrwx  1 root root    0 Jan 21 11:05 camcops.socket
^
|
The setuid bit: an indication that this is not a normal file!

12.2.6.1.4. SSL_CERTIFICATE

String. Default: none.

SSL certificate file for HTTPS (e.g. /etc/ssl/certs/ssl-cert-snakeoil.pem).

(Not applicable to the Pyramid test web server; CherryPy/Gunicorn only.)

If you host CamCOPS behind Apache, it’s likely that you’ll want Apache to handle HTTPS and CamCOPS to operate unencrypted behind a reverse proxy, in which case don’t set this or SSL_PRIVATE_KEY.

Note

If you are using CamCOPS via Docker, see here.

12.2.6.1.5. SSL_PRIVATE_KEY

String. Default: none.

SSL private key file for HTTPS (e.g. /etc/ssl/private/ssl-cert-snakeoil.key).

(Not applicable to the Pyramid test web server; CherryPy/Gunicorn only.)

Note

If you are using CamCOPS via Docker, see here.

12.2.6.1.6. STATIC_CACHE_DURATION_S

Integer. Default 86400 seconds (1 day).

Time, in seconds, for which to cache static content (e.g. logos, static scripts).

12.2.6.2. WSGI options

This section controls how CamCOPS creates its WSGI application. They apply to all Python web servers provided (CherryPy, Gunicorn, Pyramid). These options are particularly relevant if you are reverse-proxying CamCOPS behind a front-end web server such as Apache.

12.2.6.2.1. DEBUG_REVERSE_PROXY

Boolean. Default: false.

If a reverse proxy configuration is in use, show debugging information for it as WSGI variable are rewritten?

A reverse proxy configuration will be used if any of the following are set (see cardinal_pythonlib.wsgi.reverse_proxied_mw.ReverseProxiedConfig.necessary()):

PROXY_HTTP_HOST
PROXY_REMOTE_ADDR
PROXY_REWRITE_PATH_INFO
PROXY_SCRIPT_NAME
PROXY_SERVER_NAME
PROXY_SERVER_PORT
PROXY_URL_SCHEME
TRUSTED_PROXY_HEADERS

12.2.6.2.2. DEBUG_TOOLBAR

Boolean. Default: false.

Enable the Pyramid debug toolbar? This should not be enabled for production systems; it carries security risks. It will not operate via Gunicorn, which has an incompatible process model.

12.2.6.2.3. SHOW_REQUESTS

Boolean. Default: false.

Write incoming HTTP(S) requests to the server’s log stream?

12.2.6.2.4. SHOW_REQUEST_IMMEDIATELY

Boolean. Default: false.

[Only applicable if SHOW_REQUESTS is true.]

Show the request immediately, so it’s written to the log before the WSGI app does its processing, and is guaranteed to be visible even if the WSGI app hangs? The only reason to use False is probably if you intend to show response and/or timing information and you want to minimize the number of lines written to the log; in this case, only a single line is written to the log (after the wrapped WSGI app has finished processing).

12.2.6.2.5. SHOW_RESPONSE

Boolean. Default: false.

[Only applicable if SHOW_REQUESTS is true.]

Write the HTTP response code to the server’s log?

12.2.6.2.6. SHOW_TIMING

Boolean. Default: false.

[Only applicable if SHOW_REQUESTS is true.]

Write the time taken by the CamCOPS WSGI app to the server’s log?

12.2.6.2.7. PROXY_HTTP_HOST

String. Default: none.

Option to set the WSGI HTTP host directly. This affects the WSGI variable HTTP_HOST. If not specified, the variables HTTP_X_HOST, HTTP_X_FORWARDED_HOST will be used, if trusted.

It is generally easiest to leave this blank and set TRUSTED_PROXY_HEADERS instead.

12.2.6.2.8. PROXY_REMOTE_ADDR

String. Default: none.

Option to set the WSGI remote address directly. This affects the WSGI variable REMOTE_ADDR. If not specified, the variables HTTP_X_FORWARDED_FOR, HTTP_X_REAL_IP will be used, if trusted.

It is generally easiest to leave this blank and set TRUSTED_PROXY_HEADERS instead.

12.2.6.2.9. PROXY_REWRITE_PATH_INFO

Boolean. Default: false.

If SCRIPT_NAME is rewritten, this option causes PATH_INFO to be rewritten, if it starts with SCRIPT_NAME, to strip off SCRIPT_NAME. Appropriate for some front-end web browsers with limited reverse proxying support (but do not use for Apache with ProxyPass, because that rewrites incoming URLs properly).

12.2.6.2.10. PROXY_SCRIPT_NAME

String. Default: none.

Path at which this script is mounted. Set this if you are hosting this CamCOPS instance at a non-root path, unless you set trusted WSGI headers instead.

For example, if you are running an Apache server and want this instance of CamCOPS to appear at /somewhere/camcops, then (a) configure your Apache instance to proxy requests to /somewhere/camcops/... to this server (e.g. via an internal TCP/IP port or UNIX socket) and (b) specify this option.

If this option is not set, then the OS environment variable SCRIPT_NAME will be checked as well. If that is not set, the variables within HTTP_X_SCRIPT_NAME, HTTP_X_FORWARDED_SCRIPT_NAME will be used, if they are trusted.

This option affects the WSGI variables SCRIPT_NAME and PATH_INFO.

It is generally easiest to leave this blank and set TRUSTED_PROXY_HEADERS instead.

12.2.6.2.11. PROXY_SERVER_NAME

String. Default: none.

Option to set the WSGI server name directly. This affects the WSGI variable SERVER_NAME. If not specified, the variable HTTP_X_FORWARDED_SERVER will be used, if trusted.

It is generally easiest to leave this blank and set TRUSTED_PROXY_HEADERS instead.

12.2.6.2.12. PROXY_SERVER_PORT

Integer. Default: none.

Option to set the WSGI server port directly. This affects the WSGI variable SERVER_PORT. If not specified, the variable HTTP_X_FORWARDED_PORT will be used, if trusted.

It is generally easiest to leave this blank and set TRUSTED_PROXY_HEADERS instead.

12.2.6.2.13. PROXY_URL_SCHEME

String. Default: none.

Option to set the WSGI scheme (e.g. http, https) directly. This affects the WSGI variable wsgi.url_scheme. If not specified, a variable from the following will be used, if trusted: HTTP_X_FORWARDED_PROTO, HTTP_X_FORWARDED_PROTOCOL, HTTP_X_FORWARDED_SCHEME, HTTP_X_SCHEME (which can specify a protocol) or HTTP_X_FORWARDED_HTTPS, HTTP_X_FORWARDED_SSL, HTTP_X_HTTPS (which can contain Boolean information about which protocol is in use).

It is generally easiest to leave this blank and set TRUSTED_PROXY_HEADERS instead.

12.2.6.2.14. TRUSTED_PROXY_HEADERS

Multiline string.

A multiline list of strings indicating WSGI environment variables that CamCOPS should trust. Use these when CamCOPS is behind a reverse proxy (e.g. an Apache front-end web server) and you can guarantee that these variables have been set by Apache and can be trusted.

Possible values:

HTTP_X_FORWARDED_FOR
HTTP_X_FORWARDED_HOST
HTTP_X_FORWARDED_HTTPS
HTTP_X_FORWARDED_PORT
HTTP_X_FORWARDED_PROTO
HTTP_X_FORWARDED_PROTOCOL
HTTP_X_FORWARDED_SCHEME
HTTP_X_FORWARDED_SCRIPT_NAME
HTTP_X_FORWARDED_SERVER
HTTP_X_FORWARDED_SSL
HTTP_X_HOST
HTTP_X_HTTPS
HTTP_X_REAL_IP
HTTP_X_SCHEME
HTTP_X_SCRIPT_NAME

Variables that are not marked as trusted will not be used by the reverse-proxy middleware.

12.2.6.3. Determining the externally accessible CamCOPS URL for back-end work

When you browse to the CamCOPS web interface, CamCOPS can work out its own URL address, even if you are hosting CamCOPS behind a proxy (see e.g. PROXY_SCRIPT_NAME). However, CamCOPS also has a “back end”, used for scheduled and/or slow jobs like exporting tasks. If this part of CamCOPS needs to know its own address, it can’t work that out dynamically. You have to tell it.

Currently, this is primarily applicable to FHIR exports.

The components of the URL are specified like this:

For a CamCOPS server hosted at the root path (e.g. directly), leave EXTERNAL_SCRIPT_NAME blank:

https://camcops.mydomain:443/path_within_camcops_application
^^^^^   ^^^^^^^^^^^^^^^^ ^^^
|       |                |
|       |                |
|       |                EXTERNAL_SERVER_PORT
|       EXTERNAL_SERVER_NAME
EXTERNAL_URL_SCHEME

For a CamCOPS server hosted at a non-root path (e.g. via Apache as one of many pages/applications on a single web site), specify EXTERNAL_SCRIPT_NAME:

https://camcops.mydomain:443/camcops/path_within_camcops_application
^^^^^   ^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^
|       |                |   |
|       |                |   EXTERNAL_SCRIPT_NAME
|       |                EXTERNAL_SERVER_PORT
|       EXTERNAL_SERVER_NAME
EXTERNAL_URL_SCHEME

12.2.6.3.1. EXTERNAL_URL_SCHEME

String. Default: https.

See external URL configuration.

12.2.6.3.2. EXTERNAL_SERVER_NAME

String. Default: the value of HOST.

See external URL configuration.

12.2.6.3.3. EXTERNAL_SERVER_PORT

Integer. Default: the value of PORT.

See external URL configuration.

12.2.6.3.4. EXTERNAL_SCRIPT_NAME

String. Default: none.

See external URL configuration.

12.2.6.4. CherryPy options

Additional options for the CherryPy web server.

12.2.6.4.1. CHERRYPY_SERVER_NAME

String. Default: localhost.

CherryPy’s SERVER_NAME environment entry.

12.2.6.4.2. CHERRYPY_THREADS_START

Integer. Default: 10.

Number of threads for server to start with.

12.2.6.4.3. CHERRYPY_THREADS_MAX

Integer. Default: 100.

Maximum number of threads for server to use (-1 for no limit).

BEWARE exceeding the permitted number of database connections.

12.2.6.4.4. CHERRYPY_LOG_SCREEN

Boolean. Default: true.

Log access requests etc. to the terminal (stdout/stderr)?

12.2.6.4.5. CHERRYPY_ROOT_PATH

String. Default: /.

Root path to serve CRATE at, WITHIN this CherryPy web server instance.

There is unlikely to be a reason to use something other than /; do not confuse this with the mount point within a wider, e.g. Apache, configuration, which is set instead by the WSGI variable SCRIPT_NAME; see the TRUSTED_PROXY_HEADERS and PROXY_SCRIPT_NAME options.

12.2.6.5. Gunicorn options

Additional options for the Gunicorn web server.

12.2.6.5.1. GUNICORN_NUM_WORKERS

Integer. Default: twice the number of CPUs in your server.

Number of worker processes for the Gunicorn server to use.

12.2.6.5.2. GUNICORN_DEBUG_RELOAD

Boolean. Default: false.

Debugging option: reload Gunicorn upon code change?

12.2.6.5.3. GUNICORN_TIMEOUT_S

Integer. Default: 30.

Gunicorn worker timeout (s).

12.2.6.5.4. DEBUG_SHOW_GUNICORN_OPTIONS

Boolean. Default: false.

Debugging option: show possible Gunicorn settings.

12.2.7. Options for the “[export]” section

CamCOPS defines export recipients. Each export recipient defines what to export, and how to export it. For example, you might create an export recipient called perinatal_admin_team that e-mails PDFs of tasks from your perinatal psychiatry group to your perinatal psychiatry administrative team (including immediately on receipt), for manual export to a clinical records system that doesn’t support incoming electronic messages. You might create another called smith_neutrophil_study that sends XML data via HL7 v2 message, and a third called regular_database_dump that exports the entire CamCOPS database to a database on disk.

Most export recipients will use incremental export. Once CamCOPS has sent a task to a recipient, it won’t send the same task again (unless you force it to).

Exports can happen in several ways:

  • You can trigger an export manually, e.g. via camcops_server export --recipients regular_database_dump.

  • You can mark a recipient as a “push” recipient. Whenever a relevant task is uploaded to CamCOPS, CamCOPS will export it immediately.

  • You can schedule an export. Obviously, you can do this by putting the “manual” export call (as above) into an operating system schedule, such as crontab(5) (see http://en.wikipedia.org/wiki/Cron). However, CamCOPS also provides its own crontab-style scheduler, so you could have the smith_neutrophil_study export run every Tuesday at 2am.

12.2.7.1. Export control options

12.2.7.1.1. CELERY_BEAT_SCHEDULE_DATABASE

String.

Filename used by CamCOPS as the Celery Beat scheduler database. Celery may append .db (see celery beat --help).

12.2.7.1.2. CELERY_BEAT_EXTRA_ARGS

Multiline string.

Each line of this multiline string is an extra option to the celery beat command used by camcops_server launch_scheduler, after celery worker --app camcops_server --loglevel <LOGLEVEL>.

12.2.7.1.3. CELERY_BROKER_URL

String. Default: amqp://.

Broker URL for Celery. See http://docs.celeryproject.org/en/latest/userguide/configuration.html#conf-broker-settings.

Once you have enabled security in your broker, such as RabbitMQ, you will need to set this to a more secure URL (e.g. with username/password authentication).

For RabbitMQ URLs, see e.g. https://www.rabbitmq.com/uri-spec.html.

Note

If you are using CamCOPS via Docker, see here.

12.2.7.1.4. CELERY_WORKER_EXTRA_ARGS

Multiline string.

Each line of this multiline string is an extra option to the celery worker command used by camcops_server launch_workers, after celery worker --app camcops_server --loglevel <LOGLEVEL>.

Use celery worker --help to inspect the possible options. However, do not use the following options at any time (because CamCOPS does; see camcops_server.camcops_server_core.launch_celery_workers()):

  • --app

  • -O (optimization)

  • --soft-time-limit

  • --loglevel

and do not use these under Windows:

  • --concurrency

  • --pool

An example to limit to a single worker (under Linux):

CELERY_WORKER_EXTRA_ARGS =
    --concurrency=1

An example to prevent the Celery-related memory leak:

CELERY_WORKER_EXTRA_ARGS =
    --max-tasks-per-child=20

12.2.7.1.5. CELERY_EXPORT_TASK_RATE_LIMIT

String. Default: 100/m

The per worker instance rate limit for exporting CamCOPS tasks. Integer or float values are interpreted as exports per second.

The rate limits can be specified in seconds, minutes or hours by appending “/s”, “/m” or “/h” to the value.

See https://docs.celeryproject.org/en/stable/userguide/tasks.html#Task.rate_limit

12.2.7.1.6. EXPORT_LOCKDIR

String.

Directory name used for process locking for export functions.

File-based locks are held during export, so that only one export process runs at once for mutually exclusive situations (e.g. exporting the same task to the same recipient).

CamCOPS must have permissions to create files in this directory.

Under Linux, the CamCOPS installation script will create a lock directory for you. The demonstration config file will show you where this is likely to be on your system.

When the server starts, it will attempt to create this directory if it doesn’t already exist (helpful if e.g. the directory is within a temporary directory such as /var/lock under Linux that is deleted on reboot).

12.2.7.2. List of export recipients

12.2.7.2.1. RECIPIENTS

Multiline string.

This is a list of export recipients. Each recipient is defined in a config file section of its own. For example, if you have

[export]

recipients =
    recipient_A
    recipient_B

then CamCOPS expects to see, elsewhere in the config file:

[recipient:recipient_A]

# options defining recipient_A

[recipient:recipient_B]

# options defining recipient_B

12.2.7.2.2. SCHEDULE_TIMEZONE

String. Default: UTC.

Timezone used by Celery for the crontab(5)-style SCHEDULE (see below), as per http://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html#time-zones.

12.2.7.2.3. SCHEDULE

Multiline string.

Each line is in the format of crontab(5), with five time-related entries (separated by whitespace) followed by a “what to run” entry – in this case, the name of a single export recipient. Thus:

minute hour day_of_week day_of_month month_of_year recipient

For example:

0 1 * * * perinatal_group_email_recipient

which will trigger the perinatal_group_email_recipient recipient at 01:00 every day. Lines beginning with # are ignored.

Note

For scheduled exports, you must be running the CamCOPS scheduler (via camcops_server launch_scheduler) and CamCOPS workers (via camcops_server launch_workers).

12.2.8. Options for each export recipient section

The following options are applicable to a recipient definition section of the config file. Together, they define a single export recipient.

Note

An export recipient is defined by name.

This is particularly important for incremental updates. If you run an incremental export, and then make changes to the recipient definition, tasks that have already been sent will not be re-sent. (A new record will be created in the _export_recipients table with a new ID but the same recipient name, so the history is transparent.) However, if you rename the export recipient, it will be treated as a new recipient, so any tasks previously sent (via the old name) will be re-sent.

This is implemented via camcops_server.cc_modules.cc_exportmodels.get_collection_for_export() and camcops_server.cc_modules.cc_taskcollection.TaskCollection.

Config file section names are case-sensitive (see e.g. https://docs.python.org/3/library/configparser.html#supported-ini-file-structure) and so are CamCOPS export recipient names.

12.2.8.1. How to export

12.2.8.1.1. TRANSMISSION_METHOD

String.

One of the following methods:

12.2.8.1.2. PUSH

Boolean.

Treat this as a “push” recipient?

All recipients can be exported to via a manual (or automated) camcops_server export ... command. Push recipients support automatic incremental export when a task is uploaded (i.e. as soon as it’s uploaded, it’s exported).

Not all transmission methods currently support push notifications: currently database export is not supported.

Note

For push exports to function, you must be running CamCOPS workers (via camcops_server launch_workers).

Note

For speed, the front end does not check all task criteria against the recipient. It sends some tasks to the back end that the back end will reject (e.g. anonymous, out of time range, freshly finalized but previously exported). This is normal. The back end double-checks all tasks that it’s asked to export.

12.2.8.1.3. TASK_FORMAT

String.

One of the following:

  • pdf

  • html

  • xml

Not relevant for REDCap or database exports (see TRANSMISSION_METHOD).

12.2.8.1.4. XML_FIELD_COMMENTS

Boolean. Default: true.

If TASK_FORMAT = xml, then XML_FIELD_COMMENTS determines whether field comments are included. These describe the meaning of each field, so they take space but they provide more information for human readers.

12.2.8.2. What to export

12.2.8.2.1. ALL_GROUPS

Boolean. Default: false.

Export from all groups? If not, GROUPS will come into play (see below).

12.2.8.2.2. GROUPS

Multiline string.

Names of CamCOPS group(s) to export from.

Only applicable if ALL_GROUPS is false.

12.2.8.2.3. TASKS

Multiline string. Default: none (and therefore all tasks).

Tasks to export. This is a list of base table names of CamCOPS tasks (e.g. ace3, phq9) to export. If this option is not specified, all tasks are exported.

12.2.8.2.4. START_DATETIME_UTC

Date/time. May be blank.

Earliest date/time (in UTC unless otherwise specified) for which tasks will be sent. Assessed against the task’s when_created field, converted to Universal Coordinated Time (UTC). Blank to apply no start date restriction.

The parameter is named _UTC to remind you that it’s UTC if you don’t specify it more precisely (and because it’s stored as UTC in the database). However, if you want a non-UTC timezone, specify the date/time in ISO 8601 format and it will be autoconverted to UTC.

12.2.8.2.5. END_DATETIME_UTC

Date/time. May be blank.

Date/time (in UTC unless other specified) at/beyond which no tasks will be sent. Assessed against the task’s when_created field (converted to UTC). Blank to apply no end date restriction.

The parameter is named _UTC to remind you that it’s UTC if you don’t specify it more precisely (and because it’s stored as UTC in the database). However, if you want a non-UTC timezone, specify the date/time in ISO 8601 format and it will be autoconverted to UTC.

12.2.8.2.6. FINALIZED_ONLY

Boolean.

If true, only send tasks that are finalized (moved off their originating tablet and not susceptible to later modification). If false, also send tasks that are uploaded but not yet finalized (they will then be sent again if they are modified later).

Warning

It is unusual, and very likely undesirable, to set FINALIZED_ONLY to False. You may end up exporting multiple copies of tasks, all slightly different, if the user makes edits before finalizing.

12.2.8.2.7. INCLUDE_ANONYMOUS

Boolean.

Include anonymous tasks?

  • Note that anonymous tasks cannot be sent via HL7 v2; the HL7 v2 specification is heavily tied to identification.

  • Note that anonymous tasks cannot be sent via REDCap.

  • Note also that this setting operates independently of the REQUIRE_PRIMARY_IDNUM_MANDATORY_IN_POLICY setting.

12.2.8.2.8. PRIMARY_IDNUM

Integer.

Which ID number type should be considered the “internal” (primary) ID number? If specified, only tasks with this ID number present will be exported.

  • Must be specified for HL7 v2 and FHIR messages.

  • May be blank for file and e-mail transmission.

  • For (e.g.) file/e-mail transmission, this does not control the behaviour of anonymous tasks, which are instead controlled by INCLUDE_ANONYMOUS (see below).

12.2.8.2.9. REQUIRE_PRIMARY_IDNUM_MANDATORY_IN_POLICY

Boolean.

Defines behaviour relating to the primary ID number. Applies only if PRIMARY_IDNUM is set.

  • If true, no message sending will be attempted unless the PRIMARY_IDNUM is a mandatory part of the finalizing policy (and if FINALIZED_ONLY is false, also of the upload policy).

  • If false, messages will be sent, but ONLY FROM TASKS FOR WHICH THE PRIMARY_IDNUM IS PRESENT; others will be ignored.

  • If you export from multiple groups simultaneously, setting this to true means that the primary ID number must be present (as above) for all groups.

12.2.8.3. Options applicable to database export only

At present, only full (not incremental) database export is supported.

12.2.8.3.1. DB_URL

String.

SQLAlchemy URL to the receiving database.

12.2.8.3.2. DB_ECHO

Boolean. Default: false.

Echo SQL sent to the destination database.

12.2.8.3.3. DB_INCLUDE_BLOBS

Boolean. Default: true.

Include binary large objects (BLOBs) in the export?

12.2.8.3.4. DB_ADD_SUMMARIES

Boolean. Default: true.

Add summary information (including SNOMED CT codes if available)?

12.2.8.3.5. DB_PATIENT_ID_PER_ROW

Boolean. Default: false.

Add patient ID numbers to all patient rows? Used, for example, to export a database in a more convenient format for subsequent anonymisation.

The extra columns are named _patient_idnum1, _patient_idnum2, etc., according to your ID number definitions (see Patient identification).

Additionally, tables that represent “sub-tables” of tasks (e.g. trials within a task, or similar) add the fields _task_tablename and _task_pk as part of this denormalization-for-convenience.

12.2.8.4. Options applicable to e-mail export only

Attachment filenames are based on FILE_FILENAME_SPEC, but only the basename of the path is used.

General e-mail sending options are in the [site] section.

12.2.8.4.1. EMAIL_TO

Multiline string.

List of “To:” recipients.

12.2.8.4.2. EMAIL_CC

Multiline string.

List of “CC:” (carbon copy) recipients.

12.2.8.4.3. EMAIL_BCC

Multiline string.

List of “BCC:” (blind carbon copy) recipients.

12.2.8.4.4. EMAIL_PATIENT_SPEC_IF_ANONYMOUS

String.

For anonymous tasks, this string is used as the patient descriptor (see EMAIL_PATIENT_SPEC, EMAIL_SUBJECT below). Typically “anonymous”.

(Thus: as for the main PATIENT_SPEC_IF_ANONYMOUS option.)

12.2.8.4.5. EMAIL_PATIENT_SPEC

String.

String, into which substitutions will be made, that defines the patient element available for substitution into the EMAIL_SUBJECT (see below).

Options are as for the main PATIENT_SPEC option.

12.2.8.4.6. EMAIL_SUBJECT

String.

Possible substitutions are as for the main TASK_FILENAME_SPEC option.

12.2.8.4.7. EMAIL_BODY_IS_HTML

Boolean.

Is the body HTML, rather than plain text? Default false.

12.2.8.4.8. EMAIL_BODY

Multiline string.

E-mail body contents. Possible substitutions are as for the main TASK_FILENAME_SPEC option.

12.2.8.4.9. EMAIL_KEEP_MESSAGE

Boolean. Default: false.

Keep the entire message (including attachments). Turning this option on consumes lots of database space! Use only for debugging.

12.2.8.5. Options applicable to HL7 (v2) only

12.2.8.5.1. HL7_HOST

String.

HL7 hostname or IP address.

12.2.8.5.2. HL7_PORT

Integer. Default: 2575.

HL7 port.

12.2.8.5.3. HL7_PING_FIRST

Boolean. Default: true.

If true, requires a successful ping to the server prior to sending HL7 messages. (Note: this is a TCP/IP ping, and tests that the machine is up, not that it is running an HL7 server.)

12.2.8.5.4. HL7_NETWORK_TIMEOUT_MS

Integer. Default: 10000.

Network timeout (in milliseconds).

12.2.8.5.5. HL7_KEEP_MESSAGE

Boolean. Default: false.

Keep a copy of the entire message in the databaase. WARNING:* may consume significant space in the database.

12.2.8.5.6. HL7_KEEP_REPLY

Boolean. Default: false.

Keep a copy of the reply (e.g. acknowledgement) message received from the server. WARNING: may consume significant space.

12.2.8.5.7. HL7_DEBUG_DIVERT_TO_FILE

Boolean. Default: false.

Override HL7_HOST/HL7_PORT options and send HL7 messages to a (single) file instead?

This is a debugging option, allowing you to redirect HL7 messages to a file and inspect them. If chosen, the following options are used:

FILE_PATIENT_SPEC
FILE_PATIENT_SPEC_IF_ANONYMOUS
FILE_FILENAME_SPEC
FILE_MAKE_DIRECTORY
FILE_OVERWRITE_FILES

and the files are named accordingly, but with filetype set to hl7.

12.2.8.5.8. HL7_DEBUG_TREAT_DIVERTED_AS_SENT

Boolean. Default: false.

Any messages that are diverted to a file (using HL7_DEBUG_DIVERT_TO_FILE) are treated as having been sent (thus allowing the file to mimic an HL7-receiving server that’s accepting messages happily). If set to false, a diversion will allow you to preview messages for debugging purposes without “swallowing” them. BEWARE, though: if you have an automatically scheduled job (for example, to send messages every minute) and you divert with this flag set to false, you will end up with a great many message attempts!

12.2.8.6. Options applicable to HL7 FHIR (“FHIR”) only

For an overview of FHIR, see FHIR Overview from the HL7 site. For an overview of SMART on FHIR, see the SMART site, or e.g. J. Coy (2018).

CamCOPS supports exporting to FHIR servers. Thus, CamCOPS operates as a FHIR client, or “SMART App” (the system is often called “SMART on FHIR”). The server might be an electronic health record (EHR) system.

CamCOPS authenticates using the SMART App Launch Framework or “SMART on FHIR” system, as a “confidential app”. Authentication is via:

If you wish the exported “system” URLs to work, ensure the CamCOPS back-end is configured to know its own address: see external URL configuration.

For standard ID numbers, like UK NHS numbers, you should set the appropriate FHIR ID system URL.

12.2.8.6.1. FHIR_API_URL

String.

The base URL of your FHIR server’s application programming interface (API), like https://my.fhir.server/path/to/api. The server is expected to support SMART on FHIR. See:

12.2.8.6.2. FHIR_APP_ID

String. Default: camcops.

A string identifying this “app” (meaning the CamCOPS server) to the FHIR server. (The FHIR server needs to recognize this and the corresponding secret, FHIR_APP_SECRET.)

This is passed as the SMART client_id parameter (via the Python fhirclient parameter app_id).

12.2.8.6.3. FHIR_APP_SECRET

String.

A secret code that the FHIR server should recognize to identify CamCOPS as a valid client (along with the app identifier, FHIR_APP_ID).

This is passed as the SMART client_secret parameter (via the Python fhirclient parameter app_secret).

12.2.8.6.4. FHIR_LAUNCH_TOKEN

String.

This optional extra token can be passed to the FHIR server to set the context of the request. However, this may not be applicable (as such context-setting tokens may need to be very specific).

This is passed as the SMART launch parameter (via the Python fhirclient parameter launch_token).

12.2.8.6.5. FHIR_CONCURRENT

Boolean. Default: false.

Does the FHIR server handle fully concurrent (parallel) transactions? If so, you can set this to True, and CamCOPS might send lots of tasks simultaneously.

However, beware: some servers do not support full concurrency safely (see, for example, https://github.com/hapifhir/hapi-fhir/issues/3141). If you leave this setting at the default of False, then CamCOPS will switch to serial, non-concurrent transmission (one task at a time).

There is no penalty for leaving it at False except perhaps a slight reduction in speed.

12.2.8.7. Options applicable to file transfers and attachments

12.2.8.7.1. FILE_PATIENT_SPEC_IF_ANONYMOUS

String.

For anonymous tasks, this string is used as the patient descriptor (see FILE_PATIENT_SPEC, FILE_FILENAME_SPEC below). Typically “anonymous”.

(Thus: as for the main PATIENT_SPEC_IF_ANONYMOUS option.)

12.2.8.7.2. FILE_PATIENT_SPEC

String.

String, into which substitutions will be made, that defines the patient element available for substitution into the FILE_FILENAME_SPEC (see below).

Options are as for the main PATIENT_SPEC option.

12.2.8.7.3. FILE_FILENAME_SPEC

String.

String into which substitutions will be made to determine the filename to be used for each file. (Patient details are determined by FILE_PATIENT_SPEC and FILE_PATIENT_SPEC_IF_ANONYMOUS.)

Possible substitutions are as for the main TASK_FILENAME_SPEC option.

12.2.8.7.4. FILE_MAKE_DIRECTORY

Boolean. Default: false.

Make the directory if it doesn’t already exist.

12.2.8.7.5. FILE_OVERWRITE_FILES

Boolean. Default: false.

Whether or not to attempt overwriting existing files of the same name. There is a DANGER of inadvertent data loss if you set this to true.

(Needing to overwrite a file suggests that your filenames are not task-unique; try ensuring that both the tasktype and serverpk attributes are used in the filename.)

12.2.8.7.6. FILE_EXPORT_RIO_METADATA

Boolean. Default: false.

Whether or not to export a metadata file for Servelec’s RiO (https://www.servelechsc.com/servelec-hsc/products-services/rio/).

Details of this file format are in cc_task.py and camcops_server.cc_modules.cc_task.Task.get_rio_metadata().

The metadata filename is that of its associated file, but with the extension replaced by .metadata (e.g. X.pdf is accompanied by X.metadata).

If FILE_EXPORT_RIO_METADATA is true, the following options also apply: RIO_IDNUM, RIO_UPLOADING_USER, RIO_DOCUMENT_TYPE.

12.2.8.7.7. FILE_SCRIPT_AFTER_EXPORT

String. Optional.

Optional filename of a shell script or other executable to run after file export is complete. You might use this script, for example, to move the files to a different location (such as across a network). If the parameter is blank, no script will be run. If no files are exported, the script will not be run.

The parameters passed to the script are all the filenames exported for a given task. (This includes any RiO metadata filenames.)

Note:

  • WARNING: the script will execute with the same permissions as the instance of CamCOPS that’s doing the export (so, for example, if you run CamCOPS from your /etc/crontab as root, then this script will be run as root; that can pose a risk!).

  • The script executes while the export lock is still held by CamCOPS (i.e. further exports won’t be started until the script is complete).

  • If the script fails, an error message is recorded, but the file transfer is still considered to have been made (CamCOPS has done all it can and the responsibility now lies elsewhere).

  • Example test script: suppose this is /usr/local/bin/print_arguments:

    #!/usr/bin/env bash
    for f in $$@
    do
       echo "CamCOPS has just exported this file: $$f"
    done
    

    … then you could set:

    SCRIPT_AFTER_FILE_EXPORT = /usr/local/bin/print_arguments
    

12.2.8.8. Extra options for RiO metadata for file-based export

12.2.8.8.1. RIO_IDNUM

Integer. Applicable if FILE_EXPORT_RIO_METADATA is true.

Which of the ID numbers (as above) is the RiO ID?

12.2.8.8.2. RIO_UPLOADING_USER

String. Applicable if FILE_EXPORT_RIO_METADATA is true.

RiO username for the uploading user (maximum of 10 characters).

12.2.8.8.3. RIO_DOCUMENT_TYPE

String. Applicable if FILE_EXPORT_RIO_METADATA is true.

Document type as defined in the receiving RiO system. This is a code that maps to a human-readable document type; for example, the code “APT” might map to “Appointment Letter”. Typically we might want a code that maps to “Clinical Correspondence”, but the code will be defined within the local RiO system configuration.

12.2.8.9. Extra options for export to REDCap

See REDCap export.

12.2.8.9.1. REDCAP_API_URL

String.

URL of the API on the redcap instance, such as https://domain.of.redcap.server/api/.

12.2.8.9.2. REDCAP_API_KEY

String.

API key, as provided by the REDCap instance, for a user who has permissions to import and export data to and from REDCap.

In REDCap, open your project, and click “API” to see this key.

12.2.8.9.3. REDCAP_FIELDMAP_FILENAME

String.

Name of the REDCap XML fieldmap file for CamCOPS. See REDCap export.

12.2.9. Demonstration config file

Below is a specimen configuration file, generated via the command

camcops_server demo_camcops_config > demo_camcops_config.ini

Note that if you are using Docker, then the installer will give you a config file with appropriate defaults for the Docker environment (slightly different from what follows).

# Demonstration CamCOPS server configuration file.
#
# Created by CamCOPS server version 2.4.18.
# See help at https://camcops.readthedocs.io/.
#
# Using defaults for Docker environment: False

# =============================================================================
# CamCOPS site
# =============================================================================

[site]

# -----------------------------------------------------------------------------
# Database connection
# -----------------------------------------------------------------------------

DB_URL = mysql+pymysql://YYY_USERNAME_REPLACE_ME:ZZZ_PASSWORD_REPLACE_ME@localhost:3306/camcops?charset=utf8
DB_ECHO = False

# -----------------------------------------------------------------------------
# URLs and paths
# -----------------------------------------------------------------------------

LOCAL_INSTITUTION_URL = https://www.mydomain/
LOCAL_LOGO_FILE_ABSOLUTE = /path/to/camcops/server/static/logo_local.png
CAMCOPS_LOGO_FILE_ABSOLUTE = /path/to/camcops/server/static/logo_camcops.png

EXTRA_STRING_FILES = /path/to/camcops/server/extra_strings/*.xml
RESTRICTED_TASKS =
LANGUAGE = en_GB

SNOMED_TASK_XML_FILENAME =
SNOMED_ICD9_XML_FILENAME =
SNOMED_ICD10_XML_FILENAME =

WKHTMLTOPDF_FILENAME =

# -----------------------------------------------------------------------------
# Server geographical location
# -----------------------------------------------------------------------------

REGION_CODE = GB

# -----------------------------------------------------------------------------
# Login and session configuration
# -----------------------------------------------------------------------------

MFA_METHODS = no_mfa
MFA_TIMEOUT_S = 600
SESSION_COOKIE_SECRET = camcops_autogenerated_secret_YhXZQ4zVMYobWawci-zbv6nn6B6iMrZcUkGjpko4pExjwNgOpgjGh0TVzUEMt1u3DlzRGI6RJVxd8ohvKGleag==
SESSION_TIMEOUT_MINUTES = 30
SESSION_CHECK_USER_IP = True
PASSWORD_CHANGE_FREQUENCY_DAYS = 0
LOCKOUT_THRESHOLD = 10
LOCKOUT_DURATION_INCREMENT_MINUTES = 10
DISABLE_PASSWORD_AUTOCOMPLETE = True

# -----------------------------------------------------------------------------
# Suggested filenames for saving PDFs from the web view
# -----------------------------------------------------------------------------

PATIENT_SPEC_IF_ANONYMOUS = anonymous
PATIENT_SPEC = {surname}_{forename}_{allidnums}

TASK_FILENAME_SPEC = CamCOPS_{patient}_{created}_{tasktype}-{serverpk}.{filetype}
TRACKER_FILENAME_SPEC = CamCOPS_{patient}_{now}_tracker.{filetype}
CTV_FILENAME_SPEC = CamCOPS_{patient}_{now}_clinicaltextview.{filetype}

# -----------------------------------------------------------------------------
# E-mail options
# -----------------------------------------------------------------------------

EMAIL_HOST = mysmtpserver.mydomain
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USERNAME = myusername
EMAIL_HOST_PASSWORD = mypassword
EMAIL_FROM = CamCOPS computer <noreply@myinstitution.mydomain>
EMAIL_SENDER =
EMAIL_REPLY_TO = CamCOPS clinical administrator <admin@myinstitution.mydomain>

# -----------------------------------------------------------------------------
# SMS options
# -----------------------------------------------------------------------------

SMS_BACKEND = console

# -----------------------------------------------------------------------------
# User download options
# -----------------------------------------------------------------------------

PERMIT_IMMEDIATE_DOWNLOADS = False
USER_DOWNLOAD_DIR = /var/tmp/camcops
USER_DOWNLOAD_FILE_LIFETIME_MIN = 60
USER_DOWNLOAD_MAX_SPACE_MB = 100

# -----------------------------------------------------------------------------
# Debugging options
# -----------------------------------------------------------------------------

WEBVIEW_LOGLEVEL = info
CLIENT_API_LOGLEVEL = info
ALLOW_INSECURE_COOKIES = False


# =============================================================================
# Web server options
# =============================================================================

[server]

# -----------------------------------------------------------------------------
# Common web server options
# -----------------------------------------------------------------------------

HOST = 127.0.0.1
PORT = 8000
UNIX_DOMAIN_SOCKET =

# If you host CamCOPS behind Apache, it’s likely that you’ll want Apache to
# handle HTTPS and CamCOPS to operate unencrypted behind a reverse proxy, in
# which case don’t set SSL_CERTIFICATE or SSL_PRIVATE_KEY.
SSL_CERTIFICATE = 
SSL_PRIVATE_KEY = 
STATIC_CACHE_DURATION_S = 86400

# -----------------------------------------------------------------------------
# WSGI options
# -----------------------------------------------------------------------------

DEBUG_REVERSE_PROXY = False
DEBUG_TOOLBAR = False
SHOW_REQUESTS = False
SHOW_REQUEST_IMMEDIATELY = False
SHOW_RESPONSE = False
SHOW_TIMING = False
PROXY_HTTP_HOST =
PROXY_REMOTE_ADDR =
PROXY_REWRITE_PATH_INFO = False
PROXY_SCRIPT_NAME =
PROXY_SERVER_NAME =
PROXY_SERVER_PORT =
PROXY_URL_SCHEME =
TRUSTED_PROXY_HEADERS =
    HTTP_X_FORWARDED_HOST
    HTTP_X_FORWARDED_SERVER
    HTTP_X_FORWARDED_PORT
    HTTP_X_FORWARDED_PROTO
    HTTP_X_FORWARDED_FOR
    HTTP_X_SCRIPT_NAME

# -----------------------------------------------------------------------------
# Determining the externally accessible CamCOPS URL for back-end work
# -----------------------------------------------------------------------------

EXTERNAL_URL_SCHEME =
EXTERNAL_SERVER_NAME =
EXTERNAL_SERVER_PORT =
EXTERNAL_SCRIPT_NAME =

# -----------------------------------------------------------------------------
# CherryPy options
# -----------------------------------------------------------------------------

CHERRYPY_SERVER_NAME = localhost
CHERRYPY_THREADS_START = 10
CHERRYPY_THREADS_MAX = 100
CHERRYPY_LOG_SCREEN = True
CHERRYPY_ROOT_PATH = /

# -----------------------------------------------------------------------------
# Gunicorn options
# -----------------------------------------------------------------------------

GUNICORN_NUM_WORKERS = 16
GUNICORN_DEBUG_RELOAD = False
GUNICORN_TIMEOUT_S = 30
DEBUG_SHOW_GUNICORN_OPTIONS = False


# =============================================================================
# Export options
# =============================================================================

[export]

CELERY_BEAT_EXTRA_ARGS =
CELERY_BEAT_SCHEDULE_DATABASE = /var/lock/camcops/camcops_celerybeat_schedule
CELERY_BROKER_URL = amqp://
# Celery max memory per child set to be
# celery_max_mem_kilobytes / worker_concurrency (by default number of cpus/cores available)
# This example: 4GB / 4 = 1GB = 1000000
CELERY_WORKER_EXTRA_ARGS =
    --max-tasks-per-child=1000
    --max-memory-per-child=100000
CELERY_EXPORT_TASK_RATE_LIMIT = 100/m
EXPORT_LOCKDIR = /var/lock/camcops

RECIPIENTS =

SCHEDULE_TIMEZONE = UTC
SCHEDULE =


# =============================================================================
# Details for each export recipient
# =============================================================================

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Example recipient
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # Example (disabled because it's not in the RECIPIENTS list above)

[recipient:recipient_A]

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # How to export
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

TRANSMISSION_METHOD = hl7
PUSH = true
TASK_FORMAT = pdf
XML_FIELD_COMMENTS = True

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # What to export
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

ALL_GROUPS = false
GROUPS =
    myfirstgroup
    mysecondgroup
TASKS =

START_DATETIME_UTC =
END_DATETIME_UTC =
FINALIZED_ONLY = True
INCLUDE_ANONYMOUS = False
PRIMARY_IDNUM = 1
REQUIRE_PRIMARY_IDNUM_MANDATORY_IN_POLICY = True

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # Options applicable to database exports
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

DB_URL = some_sqlalchemy_url
DB_ECHO = False
DB_INCLUDE_BLOBS = True
DB_ADD_SUMMARIES = True
DB_PATIENT_ID_PER_ROW = False

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # Options applicable to e-mail exports
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

EMAIL_TO =
    Perinatal Psychiatry Admin <perinatal@myinstitution.mydomain>

EMAIL_CC =
    Dr Alice Bradford <alice.bradford@myinstitution.mydomain>
    Dr Charles Dogfoot <charles.dogfoot@myinstitution.mydomain>

EMAIL_BCC =
    superuser <root@myinstitution.mydomain>

EMAIL_PATIENT_SPEC_IF_ANONYMOUS = anonymous
EMAIL_PATIENT_SPEC = {surname}, {forename}, {allidnums}
EMAIL_SUBJECT = CamCOPS task for {patient}, created {created}: {tasktype}, PK {serverpk}
EMAIL_BODY_IS_HTML = false
EMAIL_BODY =
    Please find attached a new CamCOPS task for manual filing to the electronic
    patient record of

        {patient}

    Task type: {tasktype}
    Created: {created}
    CamCOPS server primary key: {serverpk}

    Yours faithfully,

    The CamCOPS computer.

EMAIL_KEEP_MESSAGE = False

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # Options applicable to FHIR
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

FHIR_API_URL = https://my.fhir.server/api
FHIR_APP_ID = camcops
FHIR_APP_SECRET = my_fhir_secret_abc
FHIR_LAUNCH_TOKEN =
FHIR_CONCURRENT =

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # Options applicable to HL7 (v2) exports
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

HL7_HOST = myhl7server.mydomain
HL7_PORT = 2575
HL7_PING_FIRST = True
HL7_NETWORK_TIMEOUT_MS = 10000
HL7_KEEP_MESSAGE = False
HL7_KEEP_REPLY = False
HL7_DEBUG_DIVERT_TO_FILE = False
HL7_DEBUG_TREAT_DIVERTED_AS_SENT = False

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # Options applicable to file transfers/attachments
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

FILE_PATIENT_SPEC = {surname}_{forename}_{idshortdesc1}{idnum1}
FILE_PATIENT_SPEC_IF_ANONYMOUS = anonymous
FILE_FILENAME_SPEC = /my_nfs_mount/mypath/CamCOPS_{patient}_{created}_{tasktype}-{serverpk}.{filetype}
FILE_MAKE_DIRECTORY = False
FILE_OVERWRITE_FILES = False
FILE_EXPORT_RIO_METADATA = False
FILE_SCRIPT_AFTER_EXPORT =

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # Extra options for RiO metadata for file-based export
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

RIO_IDNUM = 2
RIO_UPLOADING_USER = CamCOPS
RIO_DOCUMENT_TYPE = CC

    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # Extra options for REDCap export
    # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

REDCAP_API_URL = https://domain.of.redcap.server/api/
REDCAP_API_KEY = myapikey
REDCAP_FIELDMAP_FILENAME = /location/of/fieldmap.xml

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Example SMS Backends. No configuration needed for 'console' (testing only).
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[sms_backend:kapow]

username = myusername
password = mypassword

[sms_backend:twilio]

SID = mysid
TOKEN = mytoken
FROM_PHONE_NUMBER = myphonenumber