diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..af47c58
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,7 @@
+.git
+.gitignore
+LICENSE
+README.md
+deploy/db
+tests
+
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..79aabdb
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+deploy/db/data.sql.gz filter=lfs diff=lfs merge=lfs -text
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..19dd967
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,130 @@
+*~
+.#*
+.DS_Store
+tmp/
+.bak
+
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+#.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+
+# Grunt
+/ui/grunt
+
+# Tests tmp
+/tests/tmp/
+
+# IntelliJ
+.idea/
+
+# VS Code
+.vscode/
+
+# Custom
+deploy/request.json
+typings/
+deploy/ontologies/*.obo
+deploy/ontologies/*.owl*
+.antlr/
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..0b45d1e
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,62 @@
+##########################
+## Build env
+##########################
+FROM python:3.10-buster AS BUILD
+
+ENV DEBIAN_FRONTEND noninteractive
+
+RUN apt-get update
+#RUN apt-get upgrade -y
+RUN apt-get install -y --no-install-recommends \
+ ca-certificates pkg-config make \
+ libssl-dev libffi-dev libpq-dev
+
+# python packages
+RUN pip install --upgrade pip
+COPY requirements.txt /tmp/requirements.txt
+RUN pip install -r /tmp/requirements.txt
+
+##########################
+## Final image
+##########################
+FROM python:3.10-buster
+
+LABEL maintainer "CRG System Developers"
+LABEL org.label-schema.schema-version="2.0"
+LABEL org.label-schema.vcs-url="https://github.com/EGA-archive/beacon-2.x/"
+
+# Too much ?
+COPY --from=BUILD /usr/local/bin /usr/local/bin
+COPY --from=BUILD /usr/local/lib /usr/local/lib
+
+RUN apt-get update && \
+# apt-get upgrade -y && \
+ apt-get install -y --no-install-recommends \
+ nginx \
+ && \
+ rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/nginx.list && \
+ apt-get purge -y --auto-remove
+
+COPY deploy/nginx.conf /beacon/nginx.conf
+COPY deploy/supervisord.conf /beacon/supervisord.conf
+COPY deploy/entrypoint.sh /usr/local/bin/entrypoint.sh
+COPY beacon /beacon/beacon
+COPY ui /beacon/ui
+
+RUN groupadd beacon && \
+ useradd -M -g beacon beacon && \
+# mkdir /beacon && \
+ mkdir /var/run/beacon && \
+ chown -R beacon:beacon /beacon && \
+# chmod 400 /beacon/beacon/conf.py && \
+ chown -R beacon:beacon /var/log/nginx && \
+ chown -R beacon:beacon /var/lib/nginx && \
+ chown -R beacon:beacon /etc/nginx && \
+ chown -R beacon:beacon /var/run/beacon && \
+ mkdir -p /var/log/supervisord && \
+ chown -R beacon:beacon /var/log/supervisord && \
+ chmod +x /usr/local/bin/entrypoint.sh
+
+WORKDIR /beacon
+USER beacon
+ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..261eeb9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..2363ebe
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,40 @@
+################################################
+##
+## Makefile for Local development
+##
+################################################
+SHELL := /bin/bash
+IMG ?= egarchive/beacon
+TARGET ?= 2.0
+CONTAINER ?= beacon
+
+.PHONY: build run exec down server
+
+all: build run server
+
+build:
+ docker build $(ARGS) -t $(IMG):$(TARGET) .
+
+run: PORTS=-p 5050:5050
+up: PORTS=-p 5050:8080
+run: ENTRYPOINT=--entrypoint "/bin/sleep"
+run: CMD=1000000000000
+up run:
+ docker run -d --rm \
+ --name $(CONTAINER) \
+ $(PORTS) \
+ -v $(shell pwd)/deploy/conf.py:/beacon/beacon/conf.py \
+ -v $(shell pwd)/beacon:/beacon/beacon \
+ -v $(shell pwd)/ui/static:/beacon/static \
+ -v $(shell pwd)/ui/templates:/beacon/templates \
+ $(ENTRYPOINT) $(IMG):$(TARGET) $(CMD)
+
+exec-root: D_USER=--user root
+exec-root exec:
+ docker exec -it $(D_USER) $(CONTAINER) bash
+server:
+ docker exec -it $(CONTAINER) python -m beacon
+
+down:
+ -docker kill $(CONTAINER)
+ -docker rm $(CONTAINER)
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..bb878ce
--- /dev/null
+++ b/README.md
@@ -0,0 +1,157 @@
+# EJP-RD-Beacon-in-a-Box
+
+This repository is a modified version of the [Beacon2 Reference Implementation (B2RI)](https://github.com/EGA-archive/beacon-2.x) and contains a stand-alone Beacon instance designed to allow for
+the sharing of metadata of datasets.
+
+This repo contains:
+
+* The (Python 3.7+) [source code for beacon](beacon),
+### Local installation instructions(Docker)
+> [Instructions](deploy/README_Docker.md)
+### Local installation instructions(Dockerless)
+> [Instructions](deploy/README_Dockerless.md)
+
+### Importing metadata into the Beacon-in-a-box
+
+To import metadata into your Beacon instance please use the [Beacon-import-tools](https://github.com/Cafe-Variome/Beacon-Import-tools).
+
+
Query Endpoints
+
+## Individuals endpoint
+> Method : GET
+
+```bash
+http GET http://localhost:5050/api/individuals/
+```
+Querying this endpoit it should return all the variants of the beacon (paginated):
+
+> Method : POST
+
+```bash
+http POST http://localhost:5050/api/individuals/ --json < request.json
+```
+
+You can use POST to make the previous query. With a `request.json` file like this one:
+
+```json
+{
+ "meta": {
+ "apiVersion": "2.0"
+ },
+ "query": {
+ "filters": [
+ {
+ "id": "HP_0001252"
+ }
+ ],
+ "includeResultsetResponses": "HIT",
+ "pagination": {
+ "skip": 0,
+ "limit": 10
+ },
+ "testMode": false,
+ "requestedGranularity": "record"
+ }
+}
+```
+Above request will return all the individuals with "HP_0001252" phenotype.
+
+You can execute:
+
+
+
+But you can also use complex filters:
+
+```json
+{
+ "meta": {
+ "apiVersion": "2.0"
+ },
+ "query": {
+ "filters": [
+ {
+ "id": "obo:NCIT_C28421",
+ "value": "obo:NCIT_C16576"
+ }
+ ],
+ "includeResultsetResponses": "HIT",
+ "pagination": {
+ "skip": 0,
+ "limit": 10
+ },
+ "testMode": false,
+ "requestedGranularity": "record"
+ }
+}
+```
+## Catalogs endpoint
+> Method : GET
+
+```bash
+http GET http://localhost:5050/api/catalogs/ --json < request.json
+```
+Above request return all records.
+> Method : POST
+
+```bash
+http POST http://localhost:5050/api/catalogs/ --json < request.json
+```
+
+
Query Request Body:
+
+```JSON
+{
+"$schema": "https://json-schema.org/draft/2020-12/schema",
+ "meta":{},
+ "query": {
+ "filters": [
+ {
+ "id": "description",
+ "value": "%genome comparison%",
+ },
+ {
+ "id": "resourceTypes",
+ "value": " BiobankDataset"
+
+ }
+ ]
+ }
+}
+```
+
+**RESPONSE**
+```JSON
+{
+ "meta": {},
+
+ "responseSummary":
+ {
+ "exists": true,
+ "numTotalResults": 1
+ },
+ "response": {
+ "resultSets": [
+ {
+ "resultsCount": 1,
+ "results": [
+ {
+ "createDateTime": "2017-04-30T00:00:00+00:00",
+ "description": "The Genome in a Bottle Consortium, hosted by the National Institute of Standards and Technology (NIST) is creating reference materials and data for human genome sequencing, as well as methods for genome comparison and benchmarking. ",
+ "externalUrl": "https://www.nature.com/articles/sdata201625, https://jimb.stanford.edu/giab-resources",
+ "id": "EGAD00001008097",
+ "name": "The Genome in a Bottle Consortium (GIAB)",
+ "updateDateTime": "2017-04-30T00:00:00+00:00",
+ "resourceTypes": ["BiobankDataset"],
+ "organisation": ["UOL"]
+
+ }
+ ],
+ "resultsHandover": null
+ }
+ ]
+ },
+ "beaconHandovers": []
+ }
+```
+
+
diff --git a/beacon/__init__.py b/beacon/__init__.py
new file mode 100644
index 0000000..94dfc87
--- /dev/null
+++ b/beacon/__init__.py
@@ -0,0 +1,33 @@
+"""
+The ``beacon`` package contains code to start a Beacon Rest API.
+"""
+
+__title__ = 'Beacon v2.0'
+__version__ = VERSION = '2.0'
+__author__ = 'CRG developers'
+__license__ = 'Apache 2.0'
+__copyright__ = 'Beacon 2.0 @ CRG, Barcelona'
+
+import sys
+
+if sys.version_info < (3, 7):
+ print("beacon-python requires python 3.7 or higher", file=sys.stderr)
+ sys.exit(1)
+
+# Send warnings using the package warnings to the logging system
+# The warnings are logged to a logger named 'py.warnings' with a severity of WARNING.
+# See: https://docs.python.org/3/library/logging.html#integration-with-the-warnings-module
+import logging
+import warnings
+from logging.config import dictConfig
+from pathlib import Path
+import yaml
+
+logging.captureWarnings(True)
+warnings.simplefilter("default") # do not ignore Deprecation Warnings
+
+
+def load_logger():
+ log_file = Path(__file__).parent / "logger.yml"
+ with open(log_file, 'r') as stream:
+ dictConfig(yaml.safe_load(stream))
diff --git a/beacon/__main__.py b/beacon/__main__.py
new file mode 100644
index 0000000..c79cf2d
--- /dev/null
+++ b/beacon/__main__.py
@@ -0,0 +1,126 @@
+import base64
+import logging
+import os
+import ssl
+import sys
+from pathlib import Path
+from time import strftime
+from datetime import datetime
+
+import aiohttp_jinja2
+import jinja2
+from aiohttp import web
+from aiohttp_session import setup as session_setup
+from aiohttp_session.cookie_storage import EncryptedCookieStorage
+from cryptography import fernet
+
+from beacon import conf, load_logger
+from beacon.request import ontologies
+from beacon.response import middlewares
+from beacon.request.routes import routes
+from beacon.db import client
+
+LOG = logging.getLogger(__name__)
+
+
+async def initialize(app):
+ # Load static
+ app["static_root_url"] = "/static"
+
+ # Configure jinja
+ env = aiohttp_jinja2.get_env(app)
+ env.globals.update(
+ len=len,
+ max=max,
+ enumerate=enumerate,
+ range=range,
+ conf=conf,
+ now=strftime("%Y"),
+ )
+
+ setattr(conf, 'update_datetime', datetime.now().isoformat())
+
+ LOG.info("Initialization done.")
+
+
+async def destroy(app):
+ """Upon server close, close the DB connections."""
+ LOG.info("Shutting down.")
+ client.close()
+
+
+def main(path=None):
+ # Configure the logging
+ load_logger()
+
+ # Configure the beacon
+ beacon = web.Application(
+ middlewares=[web.normalize_path_middleware(),
+ middlewares.error_middleware]
+ )
+ beacon.on_startup.append(initialize)
+ beacon.on_cleanup.append(destroy)
+
+ # Prepare for the UI
+ main_dir = Path(__file__).parent.parent.resolve()
+ # Where the templates are
+ template_loader = jinja2.FileSystemLoader(
+ str(main_dir / "ui" / "templates"))
+ aiohttp_jinja2.setup(beacon, loader=template_loader)
+
+ # Session middleware
+ fernet_key = fernet.Fernet.generate_key()
+ secret_key = base64.urlsafe_b64decode(
+ fernet_key
+ ) # 32 url-safe base64-encoded bytes
+ storage = EncryptedCookieStorage(
+ secret_key, cookie_name=middlewares.SESSION_STORAGE
+ )
+ session_setup(beacon, storage)
+
+ # Configure the endpoints
+ beacon.add_routes(routes)
+
+ # Configure HTTPS (or not)
+ ssl_context = None
+ if getattr(conf, "beacon_tls_enabled", False):
+ use_as_client = getattr(conf, "beacon_tls_client", False)
+ sslcontext = ssl.create_default_context(
+ ssl.Purpose.CLIENT_AUTH if use_as_client else ssl.Purpose.SERVER_AUTH
+ )
+ sslcontext.load_cert_chain(
+ conf.beacon_cert, conf.beacon_key) # should exist
+ sslcontext.check_hostname = False
+ # TODO: add the CA chain
+
+ # Load ontologies
+ LOG.info("Loading ontologies... (this might take a while)")
+ ontologies.load_obo()
+ LOG.info("Finished loading the ontologies...")
+
+ # Run beacon
+ if path:
+ if os.path.exists(path):
+ os.unlink(path)
+ # will create the UDS socket and bind to it
+ web.run_app(beacon, path=path, shutdown_timeout=0,
+ ssl_context=ssl_context)
+ else:
+ static_files = Path(__file__).parent.parent.resolve() / "ui" / "static"
+ beacon.add_routes([web.static("/static", str(static_files))])
+ web.run_app(
+ beacon,
+ host=getattr(conf, "beacon_host", "0.0.0.0"),
+ port=getattr(conf, "beacon_port", 5050),
+ shutdown_timeout=0,
+ ssl_context=ssl_context,
+ )
+
+
+if __name__ == "__main__":
+ # Unix socket
+ if len(sys.argv) > 1:
+ main(path=sys.argv[1])
+ # host:port
+ else:
+ main()
diff --git a/beacon/conf.py b/beacon/conf.py
new file mode 100644
index 0000000..4177543
--- /dev/null
+++ b/beacon/conf.py
@@ -0,0 +1,118 @@
+"""Beacon Configuration."""
+
+#
+# Beacon general info
+#
+beacon_id = '' # ID of the Beacon
+beacon_name = '' # Name of the Beacon service
+api_version = 'v2.0.0' # Version of the Beacon implementation
+uri = ''
+beacon_granularity = "record"
+max_beacon_granularity = "record"
+
+#
+# Organization info
+#
+org_id = '' # Id of the organization
+org_name = '' # Full name
+org_description = ()
+org_adress = ('The University of Leicester',
+ 'University Road',
+ 'Leicester',
+ 'LE1 7RH',
+ 'United Kingdom') # filled in with a correctly formatted example
+org_welcome_url = ''
+org_contact_url = ''
+org_logo_url = ''
+org_info = ''
+
+#
+# Project info
+#
+description = (r"This Beacon "
+ r"is based on the GA4GH Beacon "
+ r"v2.0")
+version = 'v2.0'
+welcome_url = ''
+alternative_url = ''
+create_datetime = ''
+update_datetime = ''
+# update_datetime will be created when initializing the beacon, using the ISO 8601 format
+
+#
+# Service
+#
+service_type = 'org.ga4gh:beacon:1.0.0' # service type
+service_url = 'https://beacon.ega-archive.org/api/services'
+entry_point = False
+is_open = True
+# Documentation of the service
+documentation_url = 'https://github.com/EGA-archive/beacon-2.x/'
+# Environment (production, development or testing/staging deployments)
+environment = 'test'
+
+# GA4GH
+ga4gh_service_type_group = 'org.ga4gh'
+ga4gh_service_type_artifact = 'beacon'
+ga4gh_service_type_version = '1.0'
+
+# Beacon handovers
+beacon_handovers = [
+]
+
+#
+# Database connection
+#
+database_host = '127.0.0.1'
+database_port = 27017
+database_user = 'vpbib'
+database_name = 'beacon'
+database_auth_source = 'admin'
+database_password = 'vpbib'
+# database_schema = 'public' # comma-separated list of schemas
+# database_app_name = 'beacon-appname' # Useful to track connections
+
+#
+# Web server configuration
+# Note: a Unix Socket path is used when behind a server, not host:port
+#
+beacon_host = '0.0.0.0'
+beacon_port = 5050
+beacon_tls_enabled = False
+beacon_tls_client = False
+beacon_cert = '/etc/ega/server.cert'
+beacon_key = '/etc/ega/server.key'
+CA_cert = '/etc/ega/CA.cert'
+
+#
+# Permissions server configuration
+#
+permissions_url = 'http://beacon-permissions'
+
+#
+# IdP endpoints (OpenID Connect/Oauth2)
+#
+# or use Elixir AAI (see https://elixir-europe.org/services/compute/aai)
+#
+idp_client_id = ''
+idp_client_secret = '' # same as in the test IdP
+idp_scope = ''
+
+idp_authorize = ''
+idp_access_token = ''
+idp_introspection = ''
+idp_user_info = ''
+idp_logout = ''
+
+idp_redirect_uri = ''
+
+#
+# UI
+#
+autocomplete_limit = 16
+autocomplete_ellipsis = '...'
+
+#
+# Ontologies
+#
+ontologies_folder = "deploy/ontologies/"
diff --git a/beacon/db/__init__.py b/beacon/db/__init__.py
new file mode 100644
index 0000000..e49a4d3
--- /dev/null
+++ b/beacon/db/__init__.py
@@ -0,0 +1,23 @@
+from pymongo.mongo_client import MongoClient
+from beacon import conf
+import logging
+
+LOG = logging.getLogger(__name__)
+
+# client = MongoClient("mongodb://{}:{}@{}:{}/{}?authSource={}".format(
+# conf.database_user,
+# conf.database_password,
+# conf.database_host,
+# conf.database_port,
+# conf.database_name,
+# conf.database_auth_source
+# ))
+# LOG.info(client)
+# userSection = F"{conf.database_user}:{conf.database_password}@" if conf.database_user else ""
+# dbSection = F"{conf.database_host}:{conf.database_port}/{conf.database_name}{'?authSource='+ conf.database_auth_source if conf.database_auth_source else ''}"
+
+# client = MongoClient(F"mongodb://{userSection}{dbSection}")
+
+client = MongoClient("mongodb://vpbib:vpbib@beacon_db:27017/beacon?authSource=admin")
+
+
diff --git a/beacon/db/analyses.py b/beacon/db/analyses.py
new file mode 100644
index 0000000..4ef20e7
--- /dev/null
+++ b/beacon/db/analyses.py
@@ -0,0 +1,47 @@
+from typing import Optional
+from beacon.db import client
+from beacon.db.filters import apply_filters
+from beacon.db.schemas import DefaultSchemas
+from beacon.db.utils import get_documents, query_id, get_count
+from beacon.request.model import RequestParams
+
+
+def get_analyses(entry_id: Optional[str], qparams: RequestParams):
+ query = apply_filters({}, qparams.query.filters)
+ schema = DefaultSchemas.ANALYSES
+ count = get_count(client.beacon.analyses, query)
+ docs = get_documents(
+ client.beacon.analyses,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_analysis_with_id(entry_id: Optional[str], qparams: RequestParams):
+ query = apply_filters({}, qparams.query.filters)
+ query = query_id(query, entry_id)
+ schema = DefaultSchemas.ANALYSES
+ count = get_count(client.beacon.analyses, query)
+ docs = get_documents(
+ client.beacon.analyses,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_variants_of_analysis(entry_id: Optional[str], qparams: RequestParams):
+ query = {"caseLevelData.analysisId": entry_id}
+ query = apply_filters(query, qparams.query.filters)
+ schema = DefaultSchemas.GENOMICVARIATIONS
+ count = get_count(client.beacon.genomicVariations, query)
+ docs = get_documents(
+ client.beacon.genomicVariations,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
diff --git a/beacon/db/biosamples.py b/beacon/db/biosamples.py
new file mode 100644
index 0000000..d4f7c98
--- /dev/null
+++ b/beacon/db/biosamples.py
@@ -0,0 +1,75 @@
+from typing import Optional
+from beacon.db import client
+from beacon.db.filters import *
+from beacon.db.schemas import DefaultSchemas
+from beacon.db.utils import *
+from beacon.request.model import RequestParams
+
+
+def get_biosamples(entry_id: Optional[str], qparams: RequestParams):
+ query = apply_filters({}, qparams.query.filters)
+ schema = DefaultSchemas.BIOSAMPLES
+ count = get_count(client.beacon.biosamples, query)
+ docs = get_documents(
+ client.beacon.biosamples,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_biosample_with_id(entry_id: Optional[str], qparams: RequestParams):
+ query = apply_filters({}, qparams.query.filters)
+ query = query_id(query, entry_id)
+ schema = DefaultSchemas.BIOSAMPLES
+ count = get_count(client.beacon.biosamples, query)
+ docs = get_documents(
+ client.beacon.biosamples,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_variants_of_biosample(entry_id: Optional[str], qparams: RequestParams):
+ query = {"caseLevelData.biosampleId": entry_id}
+ query = apply_filters(query, qparams.query.filters)
+ schema = DefaultSchemas.GENOMICVARIATIONS
+ count = get_count(client.beacon.genomicVariations, query)
+ docs = get_documents(
+ client.beacon.genomicVariations,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_analyses_of_biosample(entry_id: Optional[str], qparams: RequestParams):
+ query = {"biosampleId": entry_id}
+ query = apply_filters(query, qparams.query.filters)
+ schema = DefaultSchemas.ANALYSES
+ count = get_count(client.beacon.analyses, query)
+ docs = get_documents(
+ client.beacon.analyses,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_runs_of_biosample(entry_id: Optional[str], qparams: RequestParams):
+ query = {"biosampleId": entry_id}
+ query = apply_filters(query, qparams.query.filters)
+ schema = DefaultSchemas.RUNS
+ count = get_count(client.beacon.runs, query)
+ docs = get_documents(
+ client.beacon.runs,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
diff --git a/beacon/db/cohorts.py b/beacon/db/cohorts.py
new file mode 100644
index 0000000..e3065df
--- /dev/null
+++ b/beacon/db/cohorts.py
@@ -0,0 +1,43 @@
+from typing import Optional
+from beacon.db.filters import apply_filters
+from beacon.db.schemas import DefaultSchemas
+from beacon.db.utils import query_id, get_count, get_documents
+from beacon.request.model import RequestParams
+from beacon.db import client
+
+
+def get_cohorts(entry_id: Optional[str], qparams: RequestParams):
+ query = apply_filters({}, qparams.query.filters)
+ schema = DefaultSchemas.COHORTS
+ count = get_count(client.beacon.cohorts, query)
+ docs = get_documents(
+ client.beacon.cohorts,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_cohort_with_id(entry_id: Optional[str], qparams: RequestParams):
+ query = apply_filters({}, qparams.query.filters)
+ query = query_id(query, entry_id)
+ schema = DefaultSchemas.COHORTS
+ count = get_count(client.beacon.cohorts, query)
+ docs = get_documents(
+ client.beacon.cohorts,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_individuals_of_cohort(entry_id: Optional[str], qparams: RequestParams):
+ # TODO
+ pass
+
+
+def get_filtering_terms_of_cohort(entry_id: Optional[str], qparams: RequestParams):
+ # TODO
+ pass
diff --git a/beacon/db/datasets.py b/beacon/db/datasets.py
new file mode 100644
index 0000000..4422af8
--- /dev/null
+++ b/beacon/db/datasets.py
@@ -0,0 +1,100 @@
+from typing import Optional
+from beacon.db.filters import apply_filters
+from beacon.db.schemas import DefaultSchemas
+from beacon.db.utils import query_id, get_count, get_documents
+from beacon.request.model import RequestParams
+from beacon.db import client
+
+import logging
+
+LOG = logging.getLogger(__name__)
+
+
+def get_datasets(entry_id: Optional[str], qparams: RequestParams):
+ query = apply_filters({}, qparams.query.filters)
+ schema = DefaultSchemas.DATASETS
+ count = get_count(client.beacon.datasets, query)
+ docs = get_documents(
+ client.beacon.datasets,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_dataset_with_id(entry_id: Optional[str], qparams: RequestParams):
+ query = apply_filters({}, qparams.query.filters)
+ query = query_id(query, entry_id)
+ schema = DefaultSchemas.DATASETS
+ count = get_count(client.beacon.datasets, query)
+ docs = get_documents(
+ client.beacon.datasets,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_variants_of_dataset(entry_id: Optional[str], qparams: RequestParams):
+ query = {"datasetId": entry_id}
+ query = apply_filters(query, qparams.query.filters)
+ schema = DefaultSchemas.GENOMICVARIATIONS
+ count = get_count(client.beacon.genomicVariations, query)
+ docs = get_documents(
+ client.beacon.genomicVariations,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_biosamples_of_dataset(entry_id: Optional[str], qparams: RequestParams):
+ query = {"datasetId": entry_id}
+ query = apply_filters(query, qparams.query.filters)
+ schema = DefaultSchemas.BIOSAMPLES
+ count = get_count(client.beacon.biosamples, query)
+ docs = get_documents(
+ client.beacon.biosamples,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_individuals_of_dataset(entry_id: Optional[str], qparams: RequestParams):
+ query = {"datasetId": entry_id}
+ query = apply_filters(query, qparams.query.filters)
+ schema = DefaultSchemas.INDIVIDUALS
+ count = get_count(client.beacon.individuals, query)
+ docs = get_documents(
+ client.beacon.individuals,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def filter_public_datasets(requested_datasets_ids):
+ query = {"dataUseConditions.duoDataUse.modifiers.id": "DUO:0000004"}
+ return client.beacon.datasets \
+ .find(query)
+
+
+def get_filtering_terms_of_dataset(entry_id: Optional[str], qparams: RequestParams):
+ # TODO
+ pass
+
+
+def get_runs_of_dataset(entry_id: Optional[str], qparams: RequestParams):
+ # TODO: To be fixed in the model
+ pass
+
+
+def get_analyses_of_dataset(entry_id: Optional[str], qparams: RequestParams):
+ # TODO: To be fixed in the model
+ pass
diff --git a/beacon/db/filtering_terms.py b/beacon/db/filtering_terms.py
new file mode 100644
index 0000000..fc3a75e
--- /dev/null
+++ b/beacon/db/filtering_terms.py
@@ -0,0 +1,90 @@
+import logging
+
+LOG = logging.getLogger(__name__)
+
+
+def get_filtering_terms():
+ filtering_terms = [
+ {
+ "type":"alphanumeric",
+ "id": "obo:NCIT_C28421",
+ "label": "Sex. Permitted values: obo:NCIT_C16576, obo:NCIT_C20197, obo:NCIT_C124294, obo:NCIT_C17998"
+ },
+ {
+ "type":"alphanumeric",
+ "id": "edam:data_2295",
+ "label": "Causative Genes"
+ },
+ {
+ "type":"alphanumeric",
+ "id": "availableMaterials",
+ "label": "Available Materials"
+
+ },
+ {
+ "type":"alphanumeric",
+ "id": "id",
+ "label": "Id of resource/dataset",
+ "scope": "Catalog"
+ },
+ {
+ "type":"alphanumeric",
+ "id": "name",
+ "label": "Name of resource/dataset",
+ "scope": "Catalog"
+ },
+ {
+ "type":"alphanumeric",
+ "id": " organisation",
+ "label": "Organisation of resource/dataset",
+ "scope": "Catalog"
+ },
+ {
+ "type":"alphanumeric",
+ "id": "resourceTypes",
+ "label": "Resource Types of resource/dataset. Permitted values: PatientRegistryDataset, BiobankDataset , KnowledgeBase ",
+ "scope": "Catalog"
+ },
+ # Ontology Filters
+ {
+ "type":"ontologyTerm",
+ "id": "obo:NCIT_C2991",
+ "label": "Disease or Disorder"
+ },
+ {
+ "type":"ontologyTerm",
+ "id": "Orphanet_558",
+ "label": "Disease or Disorder"
+ },
+ {
+ "type":"ontologyTerm",
+ "id": "sio:SIO_010056",
+ "label": "Phenotype"
+ },
+ # Numeric Filters
+ {
+ "type":"numeric",
+ "id":"obo:NCIT_C25150",
+ "label":"Age this year"
+ },
+ {
+ "type":"numeric",
+ "id":"obo:NCIT_C83164",
+ "label":"Birth Year"
+ },
+ {
+ "type":"numeric",
+ "id":"obo:NCIT_C124353",
+ "label":"Symptom Onset"
+
+ },
+ {
+ "type":"numeric",
+ "id":"obo:NCIT_C156420",
+ "label":"Age at diagnosis"
+
+ }
+
+
+ ]
+ return filtering_terms
diff --git a/beacon/db/filters.py b/beacon/db/filters.py
new file mode 100644
index 0000000..a304f71
--- /dev/null
+++ b/beacon/db/filters.py
@@ -0,0 +1,157 @@
+from ast import Str
+from collections import defaultdict
+from typing import List, Union
+import re
+import dataclasses
+from copy import deepcopy
+
+from beacon.request import ontologies
+from beacon.request.model import AlphanumericFilter, CustomFilter, NumericFilter, OntologyFilter, Operator, Similarity
+from beacon.db.filtering_terms import get_filtering_terms
+
+import logging
+
+LOG = logging.getLogger(__name__)
+
+CURIE_REGEX = r'^([a-zA-Z0-9]*):\/?[a-zA-Z0-9]*$'
+
+
+def apply_filters(query: dict, filters: List[dict]) -> dict:
+ LOG.debug("Filters len = {}".format(len(filters)))
+ if len(filters) > 0:
+ query["$and"] = []
+ partial_query = {}
+ for filter in filters:
+ if type(filter["id"]) == list:
+ partial_query = format_array_filter(filter["id"])
+ # if filter["id"].startswith('HP_') or filter["id"].startswith('Orphanet_'):
+ # filter = OntologyFilter(**filter)
+ # LOG.debug("Ontology filter: %s", filter.id)
+ # partial_query = {"$text": defaultdict(str)}
+ # partial_query = apply_ontology_filter(partial_query, filter)
+
+ elif "value" in filter:
+ filter = AlphanumericFilter(**filter)
+ value = format_value(filter.value)
+ LOG.info(type(value))
+ if(isinstance(value, int)):
+ LOG.debug("Numeric filter: %s %s %s",filter.id, filter.operator, filter.value)
+ partial_query = apply_numeric_filter(partial_query, filter)
+ else:
+ LOG.debug("Alphanumeric filter: %s %s %s",filter.id, filter.operator, filter.value)
+ partial_query = apply_alphanumeric_filter(partial_query, filter)
+ elif "similarity" in filter or "includeDescendantTerms" in filter or re.match(CURIE_REGEX, filter["id"]):
+ filter = OntologyFilter(**filter)
+ LOG.debug("Ontology filter: %s", filter.id)
+ partial_query = {"$text": defaultdict(str)}
+ partial_query = apply_ontology_filter(partial_query, filter)
+ else:
+ filter = CustomFilter(**filter)
+ LOG.debug("Custom filter: %s", filter.id)
+ partial_query = apply_custom_filter(partial_query, filter)
+ query["$and"].append(partial_query)
+ else:
+ query={}
+ return query
+
+
+def apply_ontology_filter(query: dict, filter: OntologyFilter) -> dict:
+ LOG.debug("QUERY: %s", query)
+ is_filter_id_required = True
+ q =""
+ # Search similar
+ if filter.similarity != Similarity.EXACT:
+ is_filter_id_required = False
+ similar_terms = ontologies.get_similar_ontology_terms(
+ filter.id, filter.similarity)
+ LOG.debug("Similar: {}".format(similar_terms))
+ for term in similar_terms:
+ if query["$text"]["$search"]:
+ query["$text"]["$search"] += '\"' + term + '\"'
+
+ # Apply descendant terms
+ if filter.include_descendant_terms:
+ is_filter_id_required = False
+ descendants = ontologies.get_descendants(filter.id)
+ LOG.debug("Descendants: {}".format(descendants))
+ for descendant in descendants:
+ if query["$text"]["$search"]:
+ query["$text"]["$search"] += '\"' + descendant + '\"'
+
+ if is_filter_id_required:
+ q ={"$text":{"$search": filter.id}}
+ # if filter.id.startswith('Orphanet_'):
+ # LOG.debug("QUERY: %s", query)
+ # q = {"sio:SIO_001003": {'$regex': filter.id }}
+ # elif filter.id.startswith('HP_'):
+ # q = {"sio:SIO_010056": {'$regex': filter.id }}
+
+ return q
+
+
+def format_value(value: Union[str, List[int]]) -> Union[List[int], str, int, float]:
+ if isinstance(value, list):
+ return value
+ elif value.isnumeric():
+ if float(value).is_integer():
+ return int(value)
+ else:
+ return float(value)
+ else:
+ return value
+
+
+def format_operator(operator: Operator, value: Str) -> str:
+ if operator == Operator.EQUAL:
+ if "%" in value:
+ return "$regex"
+ else:
+ return "$eq"
+ elif operator == Operator.NOT:
+ return "$ne"
+ elif operator == Operator.GREATER:
+ return "$gt"
+ elif operator == Operator.GREATER_EQUAL:
+ return "$gte"
+ elif operator == Operator.LESS:
+ return "$lt"
+ else:
+ # operator == Operator.LESS_EQUAL
+ return "$lte"
+
+
+def apply_alphanumeric_filter(query: dict, filter: AlphanumericFilter) -> dict:
+ formatted_value = format_value(filter.value)
+ formatted_operator = format_operator(filter.operator, filter.value)
+ if formatted_operator == "$regex":
+ query[filter.id] = {
+ formatted_operator: "^"+formatted_value.replace("%", ".*")+"$"}
+ else:
+ query[filter.id] = {formatted_operator: formatted_value}
+ LOG.debug("QUERY: %s", query)
+ return query
+
+
+def apply_numeric_filter(query: dict, filter: NumericFilter) -> dict:
+ formatted_operator = format_operator(filter.operator, filter.value)
+ formatted_value = int(filter.value)
+ query[filter.id] = {formatted_operator: formatted_value}
+ return query
+
+
+def apply_custom_filter(query: dict, filter: CustomFilter) -> dict:
+ LOG.info(query)
+ if "$text" in query:
+ LOG.info(query)
+ query["$text"]["$search"] += " "+'\"' + filter.id + '\"'
+ else:
+ query ={"$text":{"$search": filter.id}}
+ return query
+
+def format_array_filter(filterId:list):
+
+ search =""
+ for i in filterId:
+ search += " "+ i
+ q ={"$text":{"$search": search}}
+ return q
diff --git a/beacon/db/g_variants.py b/beacon/db/g_variants.py
new file mode 100644
index 0000000..95e561a
--- /dev/null
+++ b/beacon/db/g_variants.py
@@ -0,0 +1,219 @@
+import logging
+from typing import Dict, List, Optional
+from beacon.db.filters import apply_alphanumeric_filter, apply_filters
+from beacon.db.schemas import DefaultSchemas
+from beacon.db.utils import query_id, query_ids, get_count, get_documents
+from beacon.request.model import AlphanumericFilter, Operator, RequestParams
+from beacon.db import client
+import json
+from bson import json_util
+
+LOG = logging.getLogger(__name__)
+
+VARIANTS_PROPERTY_MAP = {
+ "assemblyId": "position.assemblyId",
+ "referenceName": "position.refseqId",
+ "start": "position.start",
+ "end": "position.end",
+ "referenceBases": "referenceBases",
+ "alternateBases": "alternateBases",
+ "variantType": "variantType",
+ "variantMinLength": None,
+ "variantMaxLength": None,
+ "mateName": None,
+ "gene": "molecularAttributes.geneIds",
+ "aachange": "molecularAttributes.aminoacidChanges"
+}
+
+def generate_position_filter_start(key: str, value: List[int]) -> List[AlphanumericFilter]:
+ LOG.debug("len value = {}".format(len(value)))
+ filters = []
+ if len(value) == 1:
+ filters.append(AlphanumericFilter(
+ id=VARIANTS_PROPERTY_MAP[key],
+ value=[value[0]],
+ operator=Operator.GREATER_EQUAL
+ ))
+ elif len(value) == 2:
+ filters.append(AlphanumericFilter(
+ id=VARIANTS_PROPERTY_MAP[key],
+ value=[value[0]],
+ operator=Operator.GREATER_EQUAL
+ ))
+ filters.append(AlphanumericFilter(
+ id=VARIANTS_PROPERTY_MAP[key],
+ value=[value[1]],
+ operator=Operator.LESS_EQUAL
+ ))
+ return filters
+
+
+def generate_position_filter_end(key: str, value: List[int]) -> List[AlphanumericFilter]:
+ LOG.debug("len value = {}".format(len(value)))
+ filters = []
+ if len(value) == 1:
+ filters.append(AlphanumericFilter(
+ id=VARIANTS_PROPERTY_MAP[key],
+ value=[value[0]],
+ operator=Operator.LESS_EQUAL
+ ))
+ elif len(value) == 2:
+ filters.append(AlphanumericFilter(
+ id=VARIANTS_PROPERTY_MAP[key],
+ value=[value[0]],
+ operator=Operator.GREATER_EQUAL
+ ))
+ filters.append(AlphanumericFilter(
+ id=VARIANTS_PROPERTY_MAP[key],
+ value=[value[1]],
+ operator=Operator.LESS_EQUAL
+ ))
+ return filters
+
+
+def apply_request_parameters(query: Dict[str, List[dict]], qparams: RequestParams):
+ LOG.debug("Request parameters len = {}".format(len(qparams.query.request_parameters)))
+ if len(qparams.query.request_parameters) > 0 and "$and" not in query:
+ query["$and"] = []
+ for k, v in qparams.query.request_parameters.items():
+ if k == "start":
+ if isinstance(v, str):
+ v = v.split(',')
+ filters = generate_position_filter_start(k, v)
+ for filter in filters:
+ query["$and"].append(apply_alphanumeric_filter({}, filter))
+ elif k == "end":
+ if isinstance(v, str):
+ v = v.split(',')
+ filters = generate_position_filter_end(k, v)
+ for filter in filters:
+ query["$and"].append(apply_alphanumeric_filter({}, filter))
+ elif k == "variantMinLength" or k == "variantMaxLength" or k == "mateName":
+ continue
+ else:
+ query["$and"].append(apply_alphanumeric_filter({}, AlphanumericFilter(
+ id=VARIANTS_PROPERTY_MAP[k],
+ value=v
+ )))
+ return query
+
+
+def get_variants(entry_id: Optional[str], qparams: RequestParams):
+ query = apply_request_parameters({}, qparams)
+ query = apply_filters(query, qparams.query.filters)
+ schema = DefaultSchemas.GENOMICVARIATIONS
+ count = get_count(client.beacon.genomicVariations, query)
+ docs = get_documents(
+ client.beacon.genomicVariations,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_variant_with_id(entry_id: Optional[str], qparams: RequestParams):
+ query = {"$and": [{"variantInternalId": entry_id}]}
+ query = apply_request_parameters(query, qparams)
+ query = apply_filters(query, qparams.query.filters)
+ schema = DefaultSchemas.GENOMICVARIATIONS
+ count = get_count(client.beacon.genomicVariations, query)
+ docs = get_documents(
+ client.beacon.genomicVariations,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_biosamples_of_variant(entry_id: Optional[str], qparams: RequestParams):
+ query = {"$and": [{"variantInternalId": entry_id}]}
+ query = apply_request_parameters(query, qparams)
+ query = apply_filters(query, qparams.query.filters)
+ biosample_ids = client.beacon.genomicVariations \
+ .find_one(query, {"caseLevelData.biosamplesId": 1, "_id": 0})
+ biosample_ids = [ r for r in biosample_ids ] if biosample_ids else []
+
+ query = apply_request_parameters({}, qparams)
+ query = query_ids(query, biosample_ids)
+ query = apply_filters(query, qparams.query.filters)
+
+ schema = DefaultSchemas.BIOSAMPLES
+ count = get_count(client.beacon.biosamples, query)
+ docs = get_documents(
+ client.beacon.biosamples,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_individuals_of_variant(entry_id: Optional[str], qparams: RequestParams):
+ query = {"$and": [{"variantInternalId": entry_id}]}
+ query = apply_request_parameters(query, qparams)
+ query = apply_filters(query, qparams.query.filters)
+ individual_ids = client.beacon.genomicVariations \
+ .find(query)
+ individual_ids = [ r["caseLevelData"]["individualId"] for r in individual_ids] if individual_ids else []
+
+ query = apply_request_parameters({}, qparams)
+ query = query_ids(query, individual_ids)
+ query = apply_filters(query, qparams.query.filters)
+
+ schema = DefaultSchemas.INDIVIDUALS
+ count = get_count(client.beacon.individuals, query)
+ docs = get_documents(
+ client.beacon.individuals,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_runs_of_variant(entry_id: Optional[str], qparams: RequestParams):
+ query = {"$and": [{"variantInternalId": entry_id}]}
+ query = apply_request_parameters(query, qparams)
+ query = apply_filters(query, qparams.query.filters)
+ run_ids = client.beacon.genomicVariations \
+ .find_one(query, {"caseLevelData.runId": 1, "_id": 0})
+ run_ids = [ r for r in run_ids] if run_ids else []
+
+ query = apply_request_parameters({}, qparams)
+ query = query_ids(query, run_ids)
+ query = apply_filters(query, qparams.query.filters)
+
+ schema = DefaultSchemas.RUNS
+ count = get_count(client.beacon.runs, query)
+ docs = get_documents(
+ client.beacon.runs,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_analyses_of_variant(entry_id: Optional[str], qparams: RequestParams):
+ query = {"$and": [{"variantInternalId": entry_id}]}
+ query = apply_request_parameters(query, qparams)
+ query = apply_filters(query, qparams.query.filters)
+ analysis_ids = client.beacon.genomicVariations \
+ .find_one(query, {"caseLevelData.analysisId": 1, "_id": 0})
+ analysis_ids = [r for r in analysis_ids] if analysis_ids else []
+
+ query = apply_request_parameters({}, qparams)
+ query = query_ids(query, analysis_ids)
+ query = apply_filters(query, qparams.query.filters)
+
+ schema = DefaultSchemas.ANALYSES
+ count = get_count(client.beacon.analyses, query)
+ docs = get_documents(
+ client.beacon.analyses,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
diff --git a/beacon/db/individuals.py b/beacon/db/individuals.py
new file mode 100644
index 0000000..87ae81b
--- /dev/null
+++ b/beacon/db/individuals.py
@@ -0,0 +1,111 @@
+from typing import Optional
+from beacon.db import client
+from beacon.db.filters import apply_filters
+from beacon.db.schemas import DefaultSchemas
+from beacon.db.utils import query_id, get_count, get_documents
+from beacon.request.model import RequestParams
+import json
+from bson import json_util
+import logging
+
+LOG = logging.getLogger(__name__)
+
+def get_individuals(entry_id: Optional[str], qparams: RequestParams):
+ query = apply_filters({}, qparams.query.filters)
+ schema = DefaultSchemas.INDIVIDUALS
+ count = get_count(client.beacon.individuals, query)
+ LOG.info(count)
+ docs = get_documents(
+ client.beacon.individuals,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_individual_with_id(entry_id: Optional[str], qparams: RequestParams):
+ query = apply_filters({}, qparams.query.filters)
+ query = query_id(query, entry_id)
+ schema = DefaultSchemas.INDIVIDUALS
+ count = get_count(client.beacon.individuals, query)
+ docs = get_documents(
+ client.beacon.individuals,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_variants_of_individual(entry_id: Optional[str], qparams: RequestParams):
+ query = {"individualId": entry_id}
+ query = apply_filters(query, qparams.query.filters)
+ schema = DefaultSchemas.GENOMICVARIATIONS
+ count = get_count(client.beacon.genomicVariations, query)
+ docs = get_documents(
+ client.beacon.genomicVariations,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_biosamples_of_individual(entry_id: Optional[str], qparams: RequestParams):
+ query = {"individualId": entry_id}
+ query = apply_filters(query, qparams.query.filters)
+ schema = DefaultSchemas.BIOSAMPLES
+ count = get_count(client.beacon.biosamples, query)
+ docs = get_documents(
+ client.beacon.biosamples,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_filtering_terms_of_individual(entry_id: Optional[str], qparams: RequestParams):
+ # TODO
+ pass
+
+
+def get_runs_of_individual(entry_id: Optional[str], qparams: RequestParams):
+ query = {"caseLevelData.individualId": entry_id}
+ query = apply_filters(query, qparams.query.filters)
+ run_ids = client.beacon.genomicVariations.find_one(query, {"caseLevelData.runId": 1, "_id": 0})
+ run_ids = [r for r in run_ids] if run_ids else []
+
+ query = query_id({}, run_ids)
+ query = apply_filters(query, qparams.query.filters)
+
+ schema = DefaultSchemas.RUNS
+ count = get_count(client.beacon.runs, query)
+ docs = get_documents(
+ client.beacon.runs,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_analyses_of_individual(entry_id: Optional[str], qparams: RequestParams):
+ query = {"caseLevelData.individualId": entry_id}
+ query = apply_filters(query, qparams.query.filters)
+ analysis_ids = client.beacon.genomicVariations.find_one(query, {"caseLevelData.analysisId": 1, "_id": 0})
+ analysis_ids = [r for r in analysis_ids] if analysis_ids else []
+
+ query = query_id({}, analysis_ids)
+ query = apply_filters(query, qparams.query.filters)
+
+ schema = DefaultSchemas.ANALYSES
+ count = get_count(client.beacon.analyses, query)
+ docs = get_documents(
+ client.beacon.analyses,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
\ No newline at end of file
diff --git a/beacon/db/runs.py b/beacon/db/runs.py
new file mode 100644
index 0000000..d13ab6a
--- /dev/null
+++ b/beacon/db/runs.py
@@ -0,0 +1,61 @@
+from typing import Optional
+from beacon.db.filters import apply_filters
+from beacon.db.schemas import DefaultSchemas
+from beacon.db.utils import query_id, get_count, get_documents
+from beacon.request.model import RequestParams
+from beacon.db import client
+
+
+def get_runs(entry_id: Optional[str], qparams: RequestParams):
+ query = apply_filters({}, qparams.query.filters)
+ schema = DefaultSchemas.RUNS
+ count = get_count(client.beacon.runs, query)
+ docs = get_documents(
+ client.beacon.runs,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_run_with_id(entry_id: Optional[str], qparams: RequestParams):
+ query = apply_filters({}, qparams.query.filters)
+ query = query_id(query, entry_id)
+ schema = DefaultSchemas.RUNS
+ count = get_count(client.beacon.runs, query)
+ docs = get_documents(
+ client.beacon.runs,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_variants_of_run(entry_id: Optional[str], qparams: RequestParams):
+ query = {"caseLevelData.runId": entry_id}
+ query = apply_filters(query, qparams.query.filters)
+ schema = DefaultSchemas.GENOMICVARIATIONS
+ count = get_count(client.beacon.genomicVariations, query)
+ docs = get_documents(
+ client.beacon.runs,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
+
+
+def get_analyses_of_run(entry_id: Optional[str], qparams: RequestParams):
+ query = {"runId": entry_id}
+ query = apply_filters(query, qparams.query.filters)
+ schema = DefaultSchemas.ANALYSES
+ count = get_count(client.beacon.analyses, query)
+ docs = get_documents(
+ client.beacon.analyses,
+ query,
+ qparams.query.pagination.skip,
+ qparams.query.pagination.limit
+ )
+ return schema, count, docs
diff --git a/beacon/db/schemas.py b/beacon/db/schemas.py
new file mode 100644
index 0000000..02c53b7
--- /dev/null
+++ b/beacon/db/schemas.py
@@ -0,0 +1,11 @@
+from enum import Enum
+
+
+class DefaultSchemas(Enum):
+ DATASETS = {"entityType": "catalogs", "schema": "vp_catalogs-v1.0"}
+ INDIVIDUALS = {"entityType": "individual", "schema": "ejp-individuals_v1.0"}
+ ANALYSES = {"entityType": "analysis", "schema": "beacon-analysis-v2.0.0"}
+ BIOSAMPLES = {"entityType": "biosample", "schema": "beacon-dataset-v2.0.0"}
+ COHORTS = {"entityType": "cohort", "schema": "beacon-cohort-v2.0.0"}
+ GENOMICVARIATIONS = {"entityType": "genomicVariation", "schema": "beacon-g_variant-v2.0.0"}
+ RUNS = {"entityType": "run", "schema": "beacon-run-v2.0.0"}
diff --git a/beacon/db/utils.py b/beacon/db/utils.py
new file mode 100644
index 0000000..1e22cd6
--- /dev/null
+++ b/beacon/db/utils.py
@@ -0,0 +1,39 @@
+from typing import Dict
+
+from pymongo.cursor import Cursor
+from pymongo.collection import Collection
+from beacon.db import client
+from beacon.request.model import RequestParams
+import logging
+
+LOG = logging.getLogger(__name__)
+
+
+def query_id(query: dict, document_id) -> dict:
+ query["id"] = document_id
+ return query
+
+
+def query_ids(query: dict, ids) -> dict:
+ query["id"] = ids
+ return query
+
+
+def query_property(query: dict, property_id: str, value: str, property_map: Dict[str, str]) -> dict:
+ query[property_map[property_id]] = value
+ return query
+
+
+def get_count(collection: Collection, query: dict) -> int:
+
+ if not query:
+ return collection.estimated_document_count()
+ else:
+ LOG.debug("FINAL QUERY (Record): {}".format(query))
+ LOG.debug("Returning Records")
+ return collection.count_documents(query)
+
+
+def get_documents(collection: Collection, query: dict, skip: int, limit: int) -> Cursor:
+ LOG.info("FINAL QUERY: {}".format(query))
+ return collection.find(query, {'_id': False}).skip(skip).limit(limit).max_time_ms(10 * 1000)
diff --git a/beacon/logger.yml b/beacon/logger.yml
new file mode 100644
index 0000000..fc735f0
--- /dev/null
+++ b/beacon/logger.yml
@@ -0,0 +1,32 @@
+---
+version: 1
+#disable_existing_loggers: True
+root:
+ level: NOTSET
+ handlers: [ noHandler ]
+
+loggers:
+ __main__:
+ level: DEBUG
+ handlers: [ console ]
+ beacon:
+ level: DEBUG
+ handlers: [ console ]
+ propagate: True
+ aiohttp:
+ level: INFO
+ handlers: [ console ]
+
+handlers:
+ noHandler:
+ class: logging.NullHandler
+ level: NOTSET
+ console:
+ class: logging.StreamHandler
+ formatter: simple
+ stream: ext://sys.stderr
+
+formatters:
+ simple:
+ format: "[{name:^10}][{levelname:^6}] (L{lineno}) {message}"
+ style: "{"
diff --git a/beacon/request/__init__.py b/beacon/request/__init__.py
new file mode 100644
index 0000000..c1c66c5
--- /dev/null
+++ b/beacon/request/__init__.py
@@ -0,0 +1,4 @@
+from aiohttp.web_request import Request
+from beacon.request.model import IncludeResultsetResponses, RequestParams
+
+import logging
diff --git a/beacon/request/handlers.py b/beacon/request/handlers.py
new file mode 100644
index 0000000..4ddcb95
--- /dev/null
+++ b/beacon/request/handlers.py
@@ -0,0 +1,104 @@
+import json
+import logging
+from aiohttp import web
+from aiohttp.web_request import Request
+from bson import json_util
+from beacon.request.validate_filters import validate_filters
+
+from beacon.request import ontologies
+from beacon.request.model import Granularity, RequestParams
+from beacon.response.build_response import (
+ build_beacon_resultset_response,
+ build_beacon_collection_response,
+ build_beacon_boolean_response,
+ build_beacon_count_response,
+ build_error_response,
+ build_filtering_terms_response
+)
+from beacon.utils.stream import json_stream
+
+LOG = logging.getLogger(__name__)
+
+
+def collection_handler(db_fn, request=None):
+ async def wrapper(request: Request):
+
+ # Get params
+ json_body = await request.text() if request.method == "POST" and request.has_body and request.can_read_body else {}
+ qparams = RequestParams(**json_body).from_request(request)
+ entry_id = request.match_info["id"] if "id" in request.match_info else None
+
+ # Get response
+ entity_schema, count, records = db_fn(entry_id, qparams)
+ response_converted = (
+ [r for r in records] if records else []
+ )
+ response = build_beacon_collection_response(
+ response_converted, count, qparams, lambda x, y: x, entity_schema
+ )
+ return await json_stream(request, response)
+
+ return wrapper
+
+
+def generic_handler(db_fn, request=None):
+ async def wrapper(request: Request):
+
+ # Get params
+ LOG.debug(request.url)
+ json_body = await request.json() if request.method == "POST" and request.can_read_body else {}
+ qparams = RequestParams(**json_body).from_request(request)
+
+ ############
+ # Check for any filters which are not part of this beacon instance and return an error
+ ############
+ # invalid_filters = validate_filters(json_body)
+ # if invalid_filters != set():
+ # error = {
+ # "errorCode": "400",
+ # "errorMessage": F"invalid Filters provided: {', '.join(invalid_filters)}"
+ # }
+ # response = build_error_response(error, qparams, None)
+ # return await json_stream(request, response)
+ # ##############
+ # else:
+ entry_id = request.match_info.get('id', None)
+
+ # Get response
+ entity_schema, count, records = db_fn(entry_id, qparams)
+ response_converted = records
+
+ response = None
+ if qparams.query.requested_granularity == Granularity.BOOLEAN:
+ response = build_beacon_boolean_response(
+ response_converted, count, qparams, lambda x, y: x, entity_schema)
+ elif qparams.query.requested_granularity == Granularity.COUNT:
+ response = build_beacon_count_response(
+ response_converted, count, qparams, lambda x, y: x, entity_schema)
+ else:
+ response = build_beacon_resultset_response(
+ response_converted, count, qparams, lambda x, y: x, entity_schema)
+ return await json_stream(request, response)
+
+ return wrapper
+
+
+def filtering_terms_handler(db_fn, request=None):
+ async def wrapper(request: Request):
+ # Get params
+ json_body = await request.json() if request.method == "POST" and request.has_body and request.can_read_body else {}
+ qparams = RequestParams(**json_body).from_request(request)
+ entry_id = request.match_info.get('id', None)
+
+ # Get response
+ _, _, records = db_fn(entry_id, qparams)
+ response_converted = (
+ [r for r in records] if records else []
+ )
+ resources = [{"id": onto.name, "url": onto.base_iri}
+ for onto in ontologies.ONTOLOGIES.values()]
+ response = build_filtering_terms_response(
+ response_converted, resources, qparams)
+ return await json_stream(request, response)
+
+ return wrapper
diff --git a/beacon/request/model.py b/beacon/request/model.py
new file mode 100644
index 0000000..5fa87fe
--- /dev/null
+++ b/beacon/request/model.py
@@ -0,0 +1,127 @@
+import logging
+from typing_extensions import Self
+from pydantic import BaseModel
+from strenum import StrEnum
+from typing import List, Optional, Union
+from beacon import conf
+from humps.main import camelize
+from aiohttp.web_request import Request
+
+LOG = logging.getLogger(__name__)
+
+
+class CamelModel(BaseModel):
+ class Config:
+ alias_generator = camelize
+ allow_population_by_field_name = True
+
+
+class IncludeResultsetResponses(StrEnum):
+ ALL = "ALL",
+ HIT = "HIT",
+ MISS = "MISS",
+ NONE = "NONE"
+
+
+class Similarity(StrEnum):
+ EXACT = "exact",
+ HIGH = "high",
+ MEDIUM = "medium",
+ LOW = "low"
+
+
+class Operator(StrEnum):
+ EQUAL = "=",
+ LESS = "<",
+ GREATER = ">",
+ NOT = "!",
+ LESS_EQUAL = "<=",
+ GREATER_EQUAL = ">="
+
+
+class Granularity(StrEnum):
+ BOOLEAN = "boolean",
+ COUNT = "count",
+ RECORD = "record"
+
+
+class OntologyFilter(CamelModel):
+ id: str
+ scope: Optional[str] = None
+ include_descendant_terms: bool = False
+ similarity: Similarity = Similarity.EXACT
+
+class NumericFilter(CamelModel):
+ id:str
+ scope: Optional[str] = None
+ operator: Operator
+ value: int
+
+
+class AlphanumericFilter(CamelModel):
+ id: str
+ value: Union[str, List[int]]
+ scope: Optional[str] = None
+ operator: Operator = Operator.EQUAL
+
+class CustomFilter(CamelModel):
+ id: str
+ scope: Optional[str] = None
+
+
+class Pagination(CamelModel):
+ skip: int = 0
+ limit: int = 10
+
+
+class RequestMeta(CamelModel):
+ requested_schemas: List[dict] = []
+ api_version: str = conf.api_version
+
+
+class RequestQuery(CamelModel):
+ filters: List[dict] = []
+ include_resultset_responses: IncludeResultsetResponses = IncludeResultsetResponses.HIT
+ pagination: Pagination = Pagination()
+ request_parameters: dict = {}
+ test_mode: bool = False
+ requested_granularity: Granularity = Granularity(conf.beacon_granularity)
+
+
+class RequestParams(CamelModel):
+ meta: RequestMeta = RequestMeta()
+ query: RequestQuery = RequestQuery()
+
+ def from_request(self, request: Request) -> Self:
+ if request.method != "POST" or not request.has_body or not request.can_read_body:
+ for k, v in request.query.items():
+ if k == "requestedSchema":
+ self.meta.requested_schemas = [v]
+ elif k == "skip":
+ self.query.pagination.skip = int(v)
+ elif k == "limit":
+ self.query.pagination.limit = int(v)
+ elif k == "includeResultsetResponses":
+ self.query.include_resultset_responses = IncludeResultsetResponses(
+ v)
+ else:
+ self.query.filters.append(
+ {
+ "id": k,
+ "operator": "=",
+ "value": v
+ }
+ )
+ return self
+
+ def summary(self):
+ return {
+ "apiVersion": self.meta.api_version,
+ "requestedSchemas": self.meta.requested_schemas,
+ "filters": self.query.filters,
+ "requestParameters": self.query.request_parameters,
+ "includeResultsetResponses": self.query.include_resultset_responses,
+ "pagination": self.query.pagination.dict(),
+ "requestedGranularity": self.query.requested_granularity,
+ "testMode": self.query.test_mode
+ }
diff --git a/beacon/request/ontologies.py b/beacon/request/ontologies.py
new file mode 100644
index 0000000..512703f
--- /dev/null
+++ b/beacon/request/ontologies.py
@@ -0,0 +1,201 @@
+import re
+import fastobo
+import networkx
+from beacon.request.model import Similarity
+from pronto.ontology import Ontology
+from os import scandir, listdir
+from pathlib import Path
+
+from owlready2 import OwlReadyOntologyParsingError
+from tqdm import tqdm
+from typing import Set, List
+from beacon.db import client
+from beacon import conf
+import owlready2
+import logging
+
+LOG = logging.getLogger(__name__)
+
+ONTOLOGIES = {}
+ONTOLOGY_REGEX = re.compile(r"([_A-Za-z]+):(\w+)")
+
+
+def find_all_ontologies_used() -> Set[str]:
+ ontologies = set()
+ for c_name in ["analyses", "biosamples", "cohorts", "genomicVariations", "datasets", "individuals", "runs"]:
+ ontologies_aux = find_ontologies_used(c_name)
+ ontologies = ontologies.union(ontologies_aux)
+ return ontologies
+
+
+def find_all_ontology_terms_used() -> Set[str]:
+ ontologies = set()
+ for c_name in ["analyses", "biosamples", "cohorts", "genomicVariations", "datasets", "individuals", "runs"]:
+ ontologies_aux = find_ontology_terms_used(c_name)
+ ontologies = ontologies.union(ontologies_aux)
+ return ontologies
+
+
+def find_ontologies_used(collection_name: str) -> Set[str]:
+ ontologies = set()
+ count = client.beacon.get_collection(
+ collection_name).estimated_document_count()
+ xs = client.beacon.get_collection(collection_name).find()
+ for r in tqdm(xs, total=count):
+ matches = ONTOLOGY_REGEX.findall(str(r))
+ for match0, _ in matches:
+ ontologies.add(match0)
+ return ontologies
+
+
+def find_ontology_terms_used(collection_name: str) -> Set[str]:
+ terms = set()
+ count = client.beacon.get_collection(
+ collection_name).estimated_document_count()
+ xs = client.beacon.get_collection(collection_name).find()
+ for r in tqdm(xs, total=count):
+ matches = ONTOLOGY_REGEX.findall(str(r))
+ for match in matches:
+ terms.add(match)
+ return terms
+
+
+def load():
+ ontology_directory = conf.ontologies_folder
+ owlready2.onto_path.append(ontology_directory)
+ count = len(listdir(ontology_directory))
+ for i, filename in enumerate(tqdm(scandir(ontology_directory), total=count)):
+ if filename.is_file() and filename.name.lower().endswith(".owl"):
+ try:
+ LOG.debug("Loading ontology {} of {}".format(i, count))
+ ONTOLOGIES[filename.name[:-4]
+ ] = owlready2.get_ontology(filename.path).load()
+ except OwlReadyOntologyParsingError:
+ # TODO: Add error
+ continue
+
+
+def try_convert_owl_to_obo():
+ ontology_directory = conf.ontologies_folder
+ count = len(listdir(ontology_directory))
+ for i, filename in enumerate(tqdm(scandir(ontology_directory), total=count)):
+ new_filename = Path(filename.path).with_suffix(".obo")
+ if filename.is_file() and filename.name.lower().endswith(".owl") and not new_filename.exists():
+ LOG.debug("Transforming {} to {}".format(
+ filename.path, new_filename))
+ owl_onto: Ontology = Ontology(filename.path)
+ with open(new_filename, "wb") as f:
+ owl_onto.dump(f, format="obo")
+
+
+def load_obo():
+ try_convert_owl_to_obo()
+ ontology_directory = conf.ontologies_folder
+ count = len(listdir(ontology_directory))
+ for i, filename in enumerate(tqdm(scandir(ontology_directory), total=count)):
+ if filename.is_file() and filename.name.lower().endswith(".obo"):
+ try:
+ LOG.debug("Loading ontology {} of {} ({})".format(
+ i, count, filename.name[:-4]))
+ ONTOLOGIES[filename.name[:-4]] = fastobo.load(filename.path)
+ LOG.debug(ONTOLOGIES[filename.name[:-4]] is None)
+ except:
+ LOG.error("Loading ontology {} failed".format(filename))
+
+
+def get_descendants(term: str) -> List[str]:
+
+ ontology_id, term_id = term.split(':')
+
+ # Create ontology graph
+ # TODO: Cache should be the graph
+ knowledge_graph = networkx.DiGraph()
+ for frame in ONTOLOGIES[ontology_id]:
+ if isinstance(frame, fastobo.term.TermFrame):
+ knowledge_graph.add_node(str(frame.id))
+ for clause in frame:
+ if isinstance(clause, fastobo.term.IsAClause):
+ knowledge_graph.add_edge(str(frame.id), str(clause.term))
+ print(networkx.is_directed_acyclic_graph(knowledge_graph))
+
+ return list(networkx.descendants(knowledge_graph, term))
+
+
+def get_ontology_neighbours(term: str, depth: int) -> List[str]:
+ ontology_id, term_id = term.split(':')
+
+ LOG.info(ontology_id)
+ # Create ontology graph
+ # TODO: Cache should be the graph
+ knowledge_graph = networkx.DiGraph()
+ for frame in ONTOLOGIES[ontology_id]:
+ if isinstance(frame, fastobo.term.TermFrame):
+ knowledge_graph.add_node(str(frame.id))
+ for clause in frame:
+ if isinstance(clause, fastobo.term.IsAClause):
+ knowledge_graph.add_edge(str(frame.id), str(clause.term))
+ print(networkx.is_directed_acyclic_graph(knowledge_graph))
+
+ # Get predecessors
+ first_predecessors = set(knowledge_graph.predecessors(term))
+
+ # Get siblings
+ siblings = set()
+ for parent in first_predecessors:
+ siblings = siblings.union(set(knowledge_graph.successors(parent)))
+
+ # Get successors and predecessors with depth
+ predecessors = set(knowledge_graph.predecessors(term))
+ successors = set(knowledge_graph.successors(term))
+ for _ in range(1, depth):
+ for predecessor in predecessors:
+ predecessors = predecessors.union(
+ set(knowledge_graph.predecessors(predecessor)))
+ for successor in successors:
+ successors = successors.union(
+ set(knowledge_graph.successors(successor)))
+
+ # Combine results
+ terms = set()
+ terms.add(term)
+ terms = terms.union(predecessors)
+ terms = terms.union(siblings)
+ terms = terms.union(successors)
+
+ return list(terms)
+
+
+def get_similar_ontology_terms(term: str, similarity: Similarity) -> List[str]:
+ if similarity == Similarity.EXACT:
+ return [term]
+ elif similarity == Similarity.HIGH:
+ return get_ontology_neighbours(term, depth=1)
+ elif similarity == Similarity.MEDIUM:
+ return get_ontology_neighbours(term, depth=2)
+ else:
+ # similarity == Similarity.LOW
+ return get_ontology_neighbours(term, depth=3)
+
+
+# def get_ontology_config(ontology: owlready2.Ontology) -> Optional[Dict]:
+# ontology_url = "https://www.ebi.ac.uk/ols/api/ontologies/{}".format(
+# ontology.name)
+# try:
+# return requests.get(ontology_url).json()["config"]
+# except:
+# return None
+
+
+# def get_resources() -> List[Dict]:
+# resources = []
+# for onto in ONTOLOGIES.values():
+# ontology_config = get_ontology_config(onto)
+# resources.append({
+# "id": onto.name,
+# "name": ontology_config["title"] if ontology_config else onto.name,
+# "url": ontology_config["id"] if ontology_config else onto.base_iri,
+# "version": ontology_config["version"] if ontology_config else None,
+# "nameSpacePrefix": ontology_config["namespace"].upper() if ontology_config else None,
+# "iriPrefix": ontology_config["baseUris"][0] if ontology_config else None,
+# })
+# return resources
diff --git a/beacon/request/routes.py b/beacon/request/routes.py
new file mode 100644
index 0000000..05a92fe
--- /dev/null
+++ b/beacon/request/routes.py
@@ -0,0 +1,42 @@
+from aiohttp import web
+
+from beacon.db import analyses, biosamples, cohorts, datasets, g_variants, individuals, runs, filtering_terms
+from beacon.request.handlers import collection_handler, generic_handler, filtering_terms_handler
+from beacon.response import framework, info, service_info
+
+
+routes = [
+
+ ########################################
+ # CONFIG
+ ########################################
+ web.get('/api/', info.handler),
+ # Name added to redirect / -> /info
+ web.get('/api/info/', info.handler, name="info"),
+ web.get('/api/service-info/', service_info.handler),
+ web.get('/api/filtering_terms/',
+ filtering_terms_handler(db_fn=filtering_terms.get_filtering_terms)),
+
+ web.get('/api/configuration/', framework.configuration),
+ web.get('/api/entry_types/', framework.entry_types),
+ web.get('/api/map/', framework.beacon_map),
+
+ ########################################
+ # GET
+ ########################################
+
+ web.get('/api/catalogs/',
+ generic_handler(db_fn=datasets.get_datasets)),
+ web.get('/api/individuals/',
+ generic_handler(db_fn=individuals.get_individuals)),
+
+ ########################################
+ # POST
+ ########################################
+
+ web.post('/api/catalogs/',
+ generic_handler(db_fn=datasets.get_datasets)),
+ web.post('/api/individuals/',
+ generic_handler(db_fn=individuals.get_individuals)),
+
+]
diff --git a/beacon/request/validate_filters.py b/beacon/request/validate_filters.py
new file mode 100644
index 0000000..383741d
--- /dev/null
+++ b/beacon/request/validate_filters.py
@@ -0,0 +1,16 @@
+import logging
+from beacon.db.filtering_terms import get_filtering_terms
+
+LOG = logging.getLogger(__name__)
+
+
+def validate_filters(json_body=None):
+ if "query" not in json_body:
+ return set()
+ if "filters" not in json_body["query"]:
+ return set()
+ supported = [filter["id"] for filter in get_filtering_terms()]
+ LOG.info(set(supported))
+ supplied = [filter["id"] for filter in json_body["query"]["filters"]]
+ LOG.info(set(supplied) - set(supported))
+ return set(supplied) - set(supported)
diff --git a/beacon/response/__init__.py b/beacon/response/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/beacon/response/build_response.py b/beacon/response/build_response.py
new file mode 100644
index 0000000..56ca6dc
--- /dev/null
+++ b/beacon/response/build_response.py
@@ -0,0 +1,244 @@
+from typing import Optional
+
+from beacon import conf
+from beacon.db.schemas import DefaultSchemas
+from beacon.request import RequestParams
+
+
+def build_meta(qparams: RequestParams, entity_schema: Optional[DefaultSchemas]):
+ """"Builds the `meta` part of the response
+
+ We assume that receivedRequest is the evaluated request (qparams) sent by the user.
+ """
+
+ meta = {
+ 'beaconId': conf.beacon_id,
+ 'apiVersion': conf.api_version,
+ 'returnedGranularity': qparams.query.requested_granularity,
+ 'receivedRequestSummary': qparams.summary(),
+ 'returnedSchemas': [entity_schema.value] if entity_schema is not None else []
+ }
+ return meta
+
+
+def build_response_summary(exists, num_total_results):
+ if num_total_results is None:
+ return {
+ 'exists': exists
+ }
+ else:
+ return {
+ 'exists': exists,
+ 'numTotalResults': num_total_results
+ }
+
+
+def build_response(data, num_total_results, qparams, func):
+ """"Fills the `response` part with the correct format in `results`"""
+
+ response = {
+ 'id': '', # TODO: Set the name of the dataset/cohort
+ 'setType': '', # TODO: Set the type of collection
+ 'exists': num_total_results > 0,
+ 'resultsCount': num_total_results,
+ 'results': data,
+ # 'info': None,
+ 'resultsHandover': None, # build_results_handover
+ }
+
+ return response
+
+
+########################################
+# Resultset Response
+########################################
+
+def build_beacon_resultset_response(data,
+ num_total_results,
+ qparams: RequestParams,
+ func_response_type,
+ entity_schema: DefaultSchemas):
+ """"
+ Transform data into the Beacon response format.
+ """
+
+ beacon_response = {
+ 'meta': build_meta(qparams, entity_schema),
+ 'responseSummary': build_response_summary(num_total_results > 0, num_total_results),
+ # TODO: 'extendedInfo': build_extended_info(),
+ 'response': {
+ 'resultSets': [build_response(data, num_total_results, qparams, func_response_type)]
+ },
+ 'beaconHandovers': conf.beacon_handovers,
+ }
+ return beacon_response
+
+
+########################################
+# Count Response
+########################################
+
+
+def build_beacon_count_response(data,
+ num_total_results,
+ qparams: RequestParams,
+ func_response_type,
+ entity_schema: DefaultSchemas):
+ """"
+ Transform data into the Beacon response format.
+ """
+
+ beacon_response = {
+ 'meta': build_meta(qparams, entity_schema),
+ 'responseSummary': build_response_summary(num_total_results > 0, num_total_results),
+ # TODO: 'extendedInfo': build_extended_info(),
+ 'beaconHandovers': conf.beacon_handovers,
+ }
+ return beacon_response
+
+########################################
+# Boolean Response
+########################################
+
+
+def build_beacon_boolean_response(data,
+ num_total_results,
+ qparams: RequestParams,
+ func_response_type,
+ entity_schema: DefaultSchemas):
+ """"
+ Transform data into the Beacon response format.
+ """
+
+ beacon_response = {
+ 'meta': build_meta(qparams, entity_schema),
+ 'responseSummary': build_response_summary(num_total_results > 0, None),
+ # TODO: 'extendedInfo': build_extended_info(),
+ 'beaconHandovers': conf.beacon_handovers,
+ }
+ return beacon_response
+
+########################################
+# Collection Response
+########################################
+
+
+def build_beacon_collection_response(data, num_total_results, qparams: RequestParams, func_response_type, entity_schema: DefaultSchemas):
+ beacon_response = {
+ 'meta': build_meta(qparams, entity_schema),
+ 'responseSummary': build_response_summary(num_total_results > 0, num_total_results),
+ # TODO: 'info': build_extended_info(),
+ 'beaconHandovers': conf.beacon_handovers,
+ 'response': {
+ 'collections': func_response_type(data, qparams)
+ }
+ }
+ return beacon_response
+
+########################################
+# Info Response
+########################################
+
+
+def build_beacon_info_response(data, qparams, func_response_type, authorized_datasets=None):
+ if authorized_datasets is None:
+ authorized_datasets = []
+
+ beacon_response = {
+ 'meta': build_meta(qparams, None),
+ 'response': {
+ 'id': conf.beacon_id,
+ 'name': conf.beacon_name,
+ 'apiVersion': conf.api_version,
+ 'environment': conf.environment,
+ 'organization': {
+ 'id': conf.org_id,
+ 'name': conf.org_name,
+ 'description': conf.org_description,
+ 'address': conf.org_adress,
+ 'welcomeUrl': conf.org_welcome_url,
+ 'contactUrl': conf.org_contact_url,
+ 'logoUrl': conf.org_logo_url,
+ },
+ 'description': conf.description,
+ 'version': conf.version,
+ 'welcomeUrl': conf.welcome_url,
+ 'alternativeUrl': conf.alternative_url,
+ 'createDateTime': conf.create_datetime,
+ 'updateDateTime': conf.update_datetime,
+ 'info': {
+ 'apiVersions': {
+ 'QueryBuilder': {},
+ 'Beacon': {
+ 'v2.0.0': 'https://www508.lamp.le.ac.uk/api/'
+ }
+ },
+ 'resourceTypes': ["knowledgeBase"],
+ 'EJP-id': "3ed6370e-1bd8-4466-9f43-82abc8472289dwDAD"
+ }
+ }
+ }
+
+ return beacon_response
+
+
+########################################
+# Service Info Response
+########################################
+
+
+def build_beacon_service_info_response():
+ beacon_response = {
+ 'id': conf.beacon_id,
+ 'name': conf.beacon_name,
+ 'type': {
+ 'group': conf.ga4gh_service_type_group,
+ 'artifact': conf.ga4gh_service_type_artifact,
+ 'version': conf.ga4gh_service_type_version
+ },
+ 'description': conf.description,
+ 'organization': {
+ 'name': conf.org_name,
+ 'url': conf.org_welcome_url
+ },
+ 'contactUrl': conf.org_contact_url,
+ 'documentationUrl': conf.documentation_url,
+ 'createdAt': conf.create_datetime,
+ 'updatedAt': conf.update_datetime,
+ 'environment': conf.environment,
+ 'version': conf.version,
+ }
+
+ return beacon_response
+
+
+########################################
+# Filtering terms Response
+########################################
+
+
+def build_filtering_terms_response(filtering_terms, resources, qparams: RequestParams):
+ return {
+ "meta": build_meta(qparams, entity_schema=None),
+ "response": {
+ "resources": resources,
+ "filteringTerms": filtering_terms
+ }
+ }
+
+########################################
+# Error Response
+########################################
+
+
+def build_error_response(error,
+ qparams: RequestParams,
+ entity_schema: DefaultSchemas):
+ """"
+ Transform data into the Beacon response format.
+ """
+ beacon_response = {
+ 'error': error,
+ 'meta': build_meta(qparams, entity_schema),
+ }
+ return beacon_response
diff --git a/beacon/response/filtering_terms.py b/beacon/response/filtering_terms.py
new file mode 100644
index 0000000..d459940
--- /dev/null
+++ b/beacon/response/filtering_terms.py
@@ -0,0 +1,30 @@
+"""
+Filtering terms Endpoint.
+
+Querying the filtering terms endpoint reveals information about existing ontology filters in this beacon.
+These are stored in the DB inside the table named 'ontology_terms'.
+
+"""
+
+from beacon import conf
+from beacon.db.filtering_terms import get_filtering_terms
+from beacon.db.schemas import DefaultSchemas
+from beacon.request import RequestParams
+from beacon.utils.stream import json_stream
+
+
+async def handler(request, qparams: RequestParams, entity_schema: DefaultSchemas):
+ docs = get_filtering_terms()
+ ontology_terms = [
+ {
+ 'id': record['ontology'] + ':' + record['term'],
+ 'label': record['label']
+ }
+ async for record in docs
+ ]
+ response = {
+ 'meta': conf.beacon_id,
+ 'apiVersion': conf.api_version,
+ 'filteringTerms': ontology_terms,
+ }
+ return await json_stream(request, response)
diff --git a/beacon/response/framework.py b/beacon/response/framework.py
new file mode 100644
index 0000000..a63fdd9
--- /dev/null
+++ b/beacon/response/framework.py
@@ -0,0 +1,112 @@
+"""
+Beacon Framework Configuration Endpoints.
+"""
+
+# import logging
+
+from beacon import conf
+
+# LOG = logging.getLogger(__name__)
+from beacon.db.schemas import DefaultSchemas
+
+from beacon.utils.stream import json_stream
+
+
+def get_entry_types():
+ return {
+ "dataset": {
+ "id": "dataset",
+ "name": "EJP dataset entry",
+ "ontologyTermForThisType": {
+ "id": "ABC:123",
+ "label": "dataset"
+ },
+ "partOfSpecification": "Beacon v2.0.0",
+ "description": "A dataset available for use within EJP, this may be a catalogue, a biobank, patient registry, knowledgebase or other",
+ "defaultSchema": {
+ "id": "ejp_dataset_v1.0",
+ "name": "EJP dataset",
+ "referenceToSchemaDefinition": "",
+ "schemaVersion": "v1.0"
+ },
+ "additionalSupportedSchemas": []
+ }
+
+ }
+
+
+async def configuration(request):
+ meta = {
+ '$schema': 'https://raw.githubusercontent.com/ga4gh-beacon/beacon-framework-v2/main/responses/sections/beaconInformationalResponseMeta.json',
+ 'beaconId': conf.beacon_id,
+ 'apiVersion': conf.api_version,
+ 'returnedSchemas': []
+ }
+
+ response = {
+ '$schema': 'https://raw.githubusercontent.com/ga4gh-beacon/beacon-framework-v2/main/configuration/beaconConfigurationSchema.json',
+ 'maturityAttributes': {
+ 'productionStatus': 'DEV'
+ },
+ 'securityAttributes': {
+ 'defaultGranularity': 'record',
+ 'securityLevels': ['PUBLIC', 'REGISTERED', 'CONTROLLED']
+ },
+ 'entryTypes': get_entry_types()
+ }
+
+ configuration_json = {
+ '$schema': 'https://raw.githubusercontent.com/ga4gh-beacon/beacon-framework-v2/main/responses/beaconConfigurationResponse.json',
+ 'meta': meta,
+ 'response': response
+ }
+
+ return await json_stream(request, configuration_json)
+
+
+async def entry_types(request):
+ meta = {
+ 'beaconId': conf.beacon_id,
+ 'apiVersion': conf.api_version,
+ 'returnedSchemas': []
+ }
+
+ response = {
+ "entryTypes": get_entry_types()
+ }
+
+ entry_types_json = {
+ 'meta': meta,
+ 'response': response
+ }
+
+ return await json_stream(request, entry_types_json)
+
+
+async def beacon_map(request):
+ meta = {
+ '$schema': 'https://raw.githubusercontent.com/ga4gh-beacon/beacon-framework-v2/main/responses/sections/beaconInformationalResponseMeta.json',
+ 'beaconId': conf.beacon_id,
+ 'apiVersion': conf.api_version,
+ 'returnedSchemas': []
+ }
+
+ response = {
+ '$schema': 'https://raw.githubusercontent.com/ga4gh-beacon/beacon-framework-v2/main/configuration/beaconMapSchema.json',
+ "endpointSets": {
+ "datasets": {
+ "entryType": "datasets",
+ "openAPIEndpointsDefinition": "",
+ "rootUrl": conf.uri + "/api/datasets",
+ "endpoints": {
+ }
+ }
+ }
+ }
+
+ beacon_map_json = {
+ 'meta': meta,
+ 'response': response
+ }
+
+ return await json_stream(request, beacon_map_json)
diff --git a/beacon/response/info.py b/beacon/response/info.py
new file mode 100644
index 0000000..7cd6559
--- /dev/null
+++ b/beacon/response/info.py
@@ -0,0 +1,55 @@
+"""
+Info Endpoint.
+
+Querying the info endpoint reveals information about this beacon and its existing datasets
+and their associated metadata.
+
+* ``/`` Beacon-v1
+* ``/info`` Beacon-v1
+* ``/info?model=GA4GH-ServiceInfo-v0.1`` GA4GH
+* ``/service-info`` GA4GH
+
+"""
+
+import logging
+import json
+from aiohttp.web_request import Request
+from beacon.db.datasets import get_datasets
+from beacon.request import RequestParams
+from beacon.response.build_response import build_beacon_info_response
+from beacon.utils.auth import resolve_token
+from beacon.utils.stream import json_stream
+from bson import json_util
+
+LOG = logging.getLogger(__name__)
+
+
+async def handler(request: Request):
+ LOG.info('Running a GET info request')
+
+ # Fetch datasets info
+ json_body = await request.json() if request.method == "POST" and request.has_body and request.can_read_body else {}
+ qparams = RequestParams(**json_body).from_request(request)
+ _, _, datasets = get_datasets(None, qparams)
+ beacon_datasets = [r for r in datasets]
+
+ # all_datasets = [r['_id'] for r in beacon_datasets]
+
+ # access_token = request.headers.get('Authorization')
+ # if access_token:
+ # access_token = access_token[7:] # cut out 7 characters: len('Bearer ')
+
+ # authorized_datasets, authenticated = await resolve_token(access_token, all_datasets)
+ # if authenticated:
+ # LOG.debug('all datasets: %s', all_datasets)
+ # LOG.info('resolved datasets: %s', authorized_datasets)
+
+ # response_converted = build_beacon_info_response(beacon_datasets,
+ # qparams,
+ # lambda x, y, z: x,
+ # authorized_datasets if authenticated else [])
+ response_converted = build_beacon_info_response(beacon_datasets,
+ qparams,
+ lambda x, y, z: x,
+ [])
+ return await json_stream(request, response_converted)
diff --git a/beacon/response/middlewares.py b/beacon/response/middlewares.py
new file mode 100644
index 0000000..ec6ace4
--- /dev/null
+++ b/beacon/response/middlewares.py
@@ -0,0 +1,63 @@
+import logging
+import sys
+import traceback
+
+# import aiohttp_csrf
+import aiohttp_jinja2
+from aiohttp import web
+
+LOG = logging.getLogger(__name__)
+
+CSRF_FIELD_NAME = 'csrf_token'
+SESSION_STORAGE = 'beacon_session'
+
+error_templates = {
+ 400: '400.html',
+ 404: '404.html',
+ 500: '500.html',
+}
+
+default_errors = {
+ 400: 'Bad request',
+ 404: 'This URL does not exist',
+ 500: 'Server Error',
+}
+
+
+def handle_error(request, exc):
+ # exc is a web.HTTPException
+
+ template = error_templates.get(exc.status)
+ if not template:
+ raise exc # We don't handle it
+
+ context = {
+ 'cookies': request.cookies,
+ 'exception': exc
+ }
+ return aiohttp_jinja2.render_template(template,
+ request,
+ context)
+
+
+@web.middleware
+async def error_middleware(request, handler):
+ try:
+ return await handler(request)
+ except web.HTTPError as ex: # Just the 400's and 500's
+
+ # if the request comes from /api/*, we output the json version
+ LOG.error('Error on page %s: %s', request.path, ex)
+
+ if hasattr(ex, 'api_error'):
+ raise
+
+ # Else, we are a regular HTML response
+ if ex.status == 401: # Unauthorized
+ raise web.HTTPFound('/login')
+
+ if ex.status >= 500:
+ LOG.error('Error caught: %s', ex)
+ traceback.print_stack(file=sys.stderr)
+
+ return handle_error(request, ex)
diff --git a/beacon/response/service_info.py b/beacon/response/service_info.py
new file mode 100644
index 0000000..63d36be
--- /dev/null
+++ b/beacon/response/service_info.py
@@ -0,0 +1,12 @@
+import logging
+from aiohttp.web_request import Request
+from beacon.response.build_response import build_beacon_service_info_response
+from beacon.utils.stream import json_stream
+
+LOG = logging.getLogger(__name__)
+
+
+async def handler(request: Request):
+ LOG.info('Running a GET service info request')
+ response_converted = build_beacon_service_info_response()
+ return await json_stream(request, response_converted)
diff --git a/beacon/utils/auth.py b/beacon/utils/auth.py
new file mode 100644
index 0000000..208ed3e
--- /dev/null
+++ b/beacon/utils/auth.py
@@ -0,0 +1,36 @@
+import logging
+
+from aiohttp import ClientSession, web
+
+from beacon.db.datasets import filter_public_datasets
+from ..conf import permissions_url
+
+LOG = logging.getLogger(__name__)
+
+
+async def resolve_token(token, requested_datasets_ids):
+ # If the user is not authenticated (ie no token)
+ # we pass (requested_datasets, False) to the database function: it will filter out the datasets list, with the public ones
+ if token is None:
+ public_datasets = [ d["name"] for d in filter_public_datasets(requested_datasets_ids) ]
+ return public_datasets, False
+
+ # Otherwise, we have a token and resolve the datasets with the permissions server
+ # The permissions server will:
+ # * filter out the datasets list, with the ones the user has access to
+ # * return _all_ the datasets the user has access to, in case the datasets list is empty
+ async with ClientSession() as session:
+ async with session.post(
+ permissions_url,
+ headers={'Authorization': 'Bearer ' + token,
+ 'Accept': 'application/json'},
+ json={'datasets': list(requested_datasets_ids)}, # will set the Content-Type to application/json
+ ) as resp:
+ if resp.status > 200:
+ LOG.error('Permissions server error %d', resp.status)
+ error = await resp.text()
+ LOG.error('Error: %s', error)
+ raise web.HTTPUnauthorized(reason=error)
+
+ authorized_datasets = await resp.json()
+ return authorized_datasets, True
diff --git a/beacon/utils/json.py b/beacon/utils/json.py
new file mode 100644
index 0000000..23b897d
--- /dev/null
+++ b/beacon/utils/json.py
@@ -0,0 +1,232 @@
+import inspect
+import logging
+from dataclasses import is_dataclass
+from decimal import Decimal
+from json.encoder import py_encode_basestring_ascii
+from bson.objectid import ObjectId
+
+from asyncpg import Record
+
+from json import loads as parse_json
+
+from pymongo.cursor import Cursor
+
+LOG = logging.getLogger(__name__)
+
+_INFINITY = float('inf')
+
+
+def is_cursor(o):
+ return isinstance(o, Cursor)
+
+
+def is_list(o):
+ return (isinstance(o, (list, set, tuple)) or
+ inspect.isgenerator(o) or
+ inspect.isgeneratorfunction(o))
+
+
+def is_dict(o):
+ return isinstance(o, (dict, Record))
+
+
+def is_asyncgen(o):
+ return (inspect.isasyncgen(o) or
+ inspect.isasyncgenfunction(o))
+
+
+class jsonb(str):
+ __parsed = None
+
+ @property
+ def parsed(self):
+ """Return a JSON deserializing of itself."""
+ if self.__parsed is None:
+ self.__parsed = parse_json(self)
+ return self.__parsed
+
+
+def json_encoder(v):
+ raise NotImplementedError('We should not use json encoding')
+
+
+def json_decoder(v):
+ return jsonb(v) # just "tag" it
+
+
+# we make it compact
+_ITEM_SEPARATOR = ','
+_KEY_SEPARATOR = ':'
+
+
+def _atom(o):
+ if isinstance(o, jsonb):
+ return o
+ elif isinstance(o, str):
+ return py_encode_basestring_ascii(o)
+ elif o is None:
+ return 'null'
+ elif o is True:
+ return 'true'
+ elif o is False:
+ return 'false'
+ elif isinstance(o, int):
+ return int.__repr__(o)
+ elif isinstance(o, float):
+ if o != o:
+ return 'NaN'
+ elif o == _INFINITY:
+ return 'Infinity'
+ elif o == -_INFINITY:
+ return '-Infinity'
+ else:
+ return float.__repr__(o)
+ elif isinstance(o, Decimal):
+ return str(o) # keeps the decimals, float would truncate them
+ elif isinstance(o, ObjectId):
+ return py_encode_basestring_ascii(str(o))
+ # not a common type
+ return None
+
+
+async def _compound(o, circulars):
+ if is_dict(o):
+ async for i in _iterencode_dict(o, circulars):
+ yield i
+ elif is_list(o):
+ async for i in _iterencode_list(o, circulars):
+ yield i
+ elif is_asyncgen(o):
+ async for i in _iterencode_async_gen(o, circulars):
+ yield i
+ elif is_dataclass(o):
+ async for i in _iterencode_dataclass(o, circulars):
+ yield i
+ elif is_cursor(o):
+ async for i in _iterencode_cursor(o, circulars):
+ yield i
+ else:
+ raise TypeError(f'Unsupported type: {o.__class__.__name__}')
+
+
+async def _iterencode_list(items, circulars):
+ yield '['
+ marker = id(items)
+ if marker in circulars:
+ raise ValueError("Circular reference detected")
+ circulars[marker] = items
+ first = True
+ for item in items:
+ if first:
+ first = False
+ else:
+ yield _ITEM_SEPARATOR
+ async for i in _iterencode(item, circulars):
+ yield i
+ yield ']'
+ del circulars[marker]
+
+
+async def _iterencode_dict(d, circulars):
+ yield '{'
+ marker = id(d)
+ if marker in circulars:
+ raise ValueError("Circular reference detected")
+ circulars[marker] = d
+ first = True
+ for key, value in d.items():
+ atom_key = _atom(key)
+ if atom_key is None:
+ raise TypeError(f'keys must be str, int, float or bool, not {key.__class__.__name__}')
+ if first:
+ first = False
+ else:
+ yield _ITEM_SEPARATOR
+ yield atom_key
+ yield _KEY_SEPARATOR
+ async for item in _iterencode(value, circulars):
+ yield item
+ yield '}'
+ del circulars[marker]
+
+
+async def _iterencode_async_gen(g, circulars):
+ yield '['
+ marker = id(g)
+ if marker in circulars:
+ raise ValueError("Circular reference detected")
+ circulars[marker] = g
+ first = True
+ async for item in g:
+ if first:
+ first = False
+ else:
+ yield _ITEM_SEPARATOR
+ async for i in _iterencode(item, circulars):
+ yield i
+ yield ']'
+ del circulars[marker]
+
+
+async def _iterencode_cursor(g, circulars):
+ yield '['
+ marker = id(g)
+ if marker in circulars:
+ raise ValueError("Circular reference detected")
+ circulars[marker] = g
+ first = True
+
+ try:
+ item = g.next()
+ except:
+ item = None
+ while item:
+ if first:
+ first = False
+ else:
+ yield _ITEM_SEPARATOR
+ async for i in _iterencode(item, circulars):
+ yield i
+ try:
+ item = g.next()
+ except:
+ item = None
+ yield ']'
+ del circulars[marker]
+
+
+async def _iterencode_dataclass(d, circulars):
+ yield '{'
+ marker = id(d)
+ if marker in circulars:
+ raise ValueError("Circular reference detected")
+ circulars[marker] = d
+ first = True
+ for key in d.__dataclass_fields__:
+ value = getattr(d, key)
+ atom_key = _atom(key)
+ if atom_key is None:
+ raise TypeError(f'keys must be str, int, float or bool, not {key.__class__.__name__}')
+ if first:
+ first = False
+ else:
+ yield _ITEM_SEPARATOR
+ yield atom_key
+ yield _KEY_SEPARATOR
+ async for item in _iterencode(value, circulars):
+ yield item
+ yield '}'
+ del circulars[marker]
+
+async def _iterencode(o, circulars):
+ atom = _atom(o)
+ if atom is not None:
+ yield atom
+ else: # not an atom type
+ async for item in _compound(o, circulars):
+ yield item
+
+
+async def json_iterencode(o):
+ async for i in _iterencode(o, {}):
+ yield i
diff --git a/beacon/utils/stream.py b/beacon/utils/stream.py
new file mode 100644
index 0000000..fd671d8
--- /dev/null
+++ b/beacon/utils/stream.py
@@ -0,0 +1,53 @@
+import logging
+
+from aiohttp.http import SERVER_SOFTWARE
+from aiohttp.web import StreamResponse
+
+from beacon import conf
+from beacon.utils.json import json_iterencode
+
+LOG = logging.getLogger(__name__)
+
+_BUF_SIZE = getattr(conf, 'json_buffer_size', 1000)
+
+
+# async def json_stream(request, data):
+# from aiohttp.web import json_response as aiohttp_json_response
+# return aiohttp_json_response(data)
+
+async def json_stream(request, data, partial=False):
+ # No need here to check if partial is indeed a boolean
+
+ # Running this first, in case it raises an error
+ # so we don't start the StreamResponse yet
+ content_gen = [chunk async for chunk in json_iterencode(data)]
+
+ LOG.debug('HTTP response stream')
+ headers = {
+ 'Content-Type': 'application/json;charset=utf-8',
+ 'Server': f'{conf.beacon_name} {conf.version} (based on {SERVER_SOFTWARE})'
+ }
+ LOG.debug('Partial content: %s', partial)
+ response = StreamResponse(headers=headers, status=206 if partial else 200)
+
+ # response.enable_chunked_encoding()
+ await response.prepare(request)
+
+ # LOG.debug('HTTP response stream for rows')
+ buf = []
+ for chunk in content_gen:
+ if len(buf) < _BUF_SIZE:
+ buf.append(chunk)
+ continue
+ # flush the buffer
+ buf.append(chunk)
+ chunk = ''.join(buf)
+ buf = []
+ await response.write(chunk.encode()) # utf-8
+ if buf: # flush the remainder in the buffer
+ chunk = ''.join(buf)
+ await response.write(chunk.encode()) # utf-8
+
+ # LOG.debug('HTTP response stream closing')
+ await response.write_eof()
+ return response
diff --git a/deploy/Makefile b/deploy/Makefile
new file mode 100644
index 0000000..ce500e5
--- /dev/null
+++ b/deploy/Makefile
@@ -0,0 +1,37 @@
+all: down up load reindex rebuild
+
+load:
+ mongoimport --jsonArray --uri "mongodb://root:example@127.0.0.1:27017/beacon?authSource=admin" --file data/datasets*.json --collection datasets
+ mongoimport --jsonArray --uri "mongodb://root:example@127.0.0.1:27017/beacon?authSource=admin" --file data/individual*.json --collection individuals
+
+up-db:
+ docker-compose up -d db && \
+ docker-compose up -d mongo-express
+
+up: up-db
+ docker-compose up -d beacon
+
+rebuild:
+ docker-compose rm -sf beacon && \
+ docker-compose build beacon && \
+ docker-compose up -d beacon && \
+ docker-compose logs -f beacon
+
+logs:
+ docker-compose logs -f beacon
+
+relaunch:
+ docker-compose up beacon
+
+down:
+ docker-compose down
+
+verify:
+ beacon-verifier http://localhost:5050/api/
+
+reindex:
+ python3 reindex.py
+
+# only works with justfile (https://github.com/casey/just#recipe-parameters)
+test COLLECTION REQUEST:
+ http POST http://localhost:5050/api/{{COLLECTION}}/ --json < {{REQUEST}}
diff --git a/deploy/README_Docker.md b/deploy/README_Docker.md
new file mode 100644
index 0000000..5f93084
--- /dev/null
+++ b/deploy/README_Docker.md
@@ -0,0 +1,73 @@
+# Deployment instructions
+
+[](https://mermaid.live/edit#pako:eNp1U01vgzAM_Ssop01qdtiRw6RRWm1SD91WJk2lhxRMGw0SFEg_VvW_z4EE2pX15Lz3bD_b9EQSmQLxyUaxcuvN3mPh4S-qQC0z5meMagyb98pSr5bYc5HKPS3YgRf8B5Cwiue5k2DWDrNfFou5QS0fBneWT1nN1qwCL7TB6j4WVoTI8ktq5RmRzRzLotR1Zy2F6ruWZQdb1eSQQG4lGc-BggFa2Eo-x1NXQzDzsngwnV4kmufKGar0ut3RmwZ1bDG3Ko_SJ5y_B52jhsDJe6aPuoJrYIkU9PHh0JN2j01-GFzjYXBbFkTqjA7VrhXjgosN1fy6VvR_jei2u-0cDc5j9WYfPehmcAtpmYtOnVNzcG8mWYo2Lzoa1BRorjc0YJbRHcs5fiVSXc_WpDTJeMfBTeLhHf9nDTYgI1KAKhhP8S9yMnBM6i0UEBMfQwEaN5vHJBZnlOoSXcAk5WiF-LXSMCJM1_LjKBL3bjUhZ2i_aMHzL0zOAvw)
+
+## Prerequisites
+
+You should have installed:
+
+- [Docker](https://docs.docker.com/engine/install/)
+- [Docker Compose](https://docs.docker.com/compose/install/)
+- [MongoDB Database Tools](https://www.mongodb.com/docs/database-tools/installation/installation/) (specifically `mongoimport` to add the dummy data to the database)
+- [Python 3](https://www.python.org/downloads/)
+
+## Installation
+
+All of the commands should be executed from the deploy directory.
+
+```bash
+cd deploy
+```
+
+### Light up the database
+
+#### Up the DB
+
+```bash
+docker-compose up -d db
+docker-compose up -d mongo-express
+```
+
+With `mongo-express` we can see the contents of the database at [http://localhost:8081](http://localhost:8081).
+
+#### Load the data
+
+To load the database we execute the following commands:
+
+```bash
+mongoimport --jsonArray --uri "mongodb://vpbib:vpbib@127.0.0.1:27017/beacon?authSource=admin" --file data/datasets*.json --collection datasets
+mongoimport --jsonArray --uri "mongodb://vpbib:vpbib@127.0.0.1:27017/beacon?authSource=admin" --file data/individuals*.json --collection individuals
+```
+
+This loads the JSON files inside of the `data` folder into the MongoDB database.
+
+> You can also use `make load` as a convenience alias.
+
+#### Create the indexes
+
+You can create the necessary indexes running the following Python script:
+
+```bash
+# Install the dependencies
+pip3 install pymongo
+
+python3 reindex.py
+```
+
+### Light up the beacon
+
+#### Up the beacon
+
+Once the database is setup, you can up the beacon with the following command:
+
+```bash
+docker-compose up -d beacon
+```
+
+#### Check the logs
+
+Check the logs until the beacon is ready to be queried:
+
+```bash
+docker-compose logs -f beacon
+```
diff --git a/deploy/README_Dockerless.md b/deploy/README_Dockerless.md
new file mode 100644
index 0000000..a843d27
--- /dev/null
+++ b/deploy/README_Dockerless.md
@@ -0,0 +1,148 @@
+# Deployment instructions
+
+[](https://mermaid.live/edit#pako:eNp1U01vgzAM_Ssop01qdtiRw6RRWm1SD91WJk2lhxRMGw0SFEg_VvW_z4EE2pX15Lz3bD_b9EQSmQLxyUaxcuvN3mPh4S-qQC0z5meMagyb98pSr5bYc5HKPS3YgRf8B5Cwiue5k2DWDrNfFou5QS0fBneWT1nN1qwCL7TB6j4WVoTI8ktq5RmRzRzLotR1Zy2F6ruWZQdb1eSQQG4lGc-BggFa2Eo-x1NXQzDzsngwnV4kmufKGar0ut3RmwZ1bDG3Ko_SJ5y_B52jhsDJe6aPuoJrYIkU9PHh0JN2j01-GFzjYXBbFkTqjA7VrhXjgosN1fy6VvR_jei2u-0cDc5j9WYfPehmcAtpmYtOnVNzcG8mWYo2Lzoa1BRorjc0YJbRHcs5fiVSXc_WpDTJeMfBTeLhHf9nDTYgI1KAKhhP8S9yMnBM6i0UEBMfQwEaN5vHJBZnlOoSXcAk5WiF-LXSMCJM1_LjKBL3bjUhZ2i_aMHzL0zOAvw)
+
+## Prerequisites
+
+You should have installed:
+
+- [MongoDB Database Tools](https://www.mongodb.com/docs/database-tools/installation/installation/)
+- [Python 3](https://www.python.org/downloads/)
+
+## Installation
+
+### Light up the database
+
+#### Up the DB
+
+Install mongoDB following the instructions found here:
+[https://www.mongodb.com/try/download](https://www.mongodb.com/try/download)
+
+> *optional*: Install a program to interact with your mongoDB to view and edit the DB contents, such as [MongoDB Compass](https://www.mongodb.com/try/download/compass))
+
+
+#### Load the data
+
+Data is stored in mongoDB within collections of related JSON objects. For the use case of this implementation we will be storing metadata using following schema within the "datasets" collection and individuals in "individuals" collection.
+
+**Beaacon_Catalog schema**
+```JSON
+{
+ "$schema": "http://json-schema.org/draft-07/schema",
+ "title": "Beacon Catalog",
+ "$comment": "Beacon model",
+ "description": "Schema for a Beacon Catalog .",
+ "type": "object",
+ "required": ["id", "name"],
+ "properties": {
+ "id": {
+ "description": "Unique identifier of the dataset",
+ "type": "string",
+ "examples": ["dataset01"]
+ },
+ "name": {
+ "description": "Name of the dataset/resource",
+ "type": "string",
+ "examples": ["Cardiovascular events in over 70s"]
+ },
+ "description": {
+ "description": "Brief description of the dataset",
+ "type": "string",
+ "examples": ["Project for inferring relationships between cardiovascular events and age"]
+ },
+
+ "resourceType": {
+ "description": "The primary resource type for this resource.",
+ "type": "string",
+ "example" : "PatientRegistryDataset",
+ "enum": [
+ "PatientRegistryDataset", "BiobankDataset", "KnowledgeBase"
+ ]
+ },
+ "createDateTime": {
+ "$ref": "https://raw.githubusercontent.com/ga4gh-beacon/beacon-v2-Models/main/BEACON-V2-Model/common/commonDefinitions.json#/definitions/Timestamp",
+ "description": "The time the dataset was created (ISO 8601 format)",
+ "examples": [
+ "2017-01-17T20:33:40Z"
+ ]
+ },
+ "updateDateTime": {
+ "$ref": "https://raw.githubusercontent.com/ga4gh-beacon/beacon-v2-Models/main/BEACON-V2-Model/common/commonDefinitions.json#/definitions/Timestamp",
+ "description": "The time the dataset was updated in (ISO 8601 format)",
+ "examples": [
+ "2017-01-17T20:33:40Z"
+ ]
+ },
+ "version": {
+ "type": "string",
+ "description": "Version of the dataset",
+ "examples": [
+ "v1.1"
+ ]
+ },
+ "externalUrl": {
+ "type": "string",
+ "format": "uri",
+ "description": "URL to an external system providing more dataset information (RFC 3986 format).",
+ "examples": [
+ "http://example.org/wiki/Main_Page"
+ ]
+ },
+
+ "organisations": {
+ "description": "Organisation(s) responsible for the processing of data access requests made to this dataset",
+ "type": "array",
+ "items": {
+ "description": "Organisation responsible for the processing of data access requests made to this dataset",
+ "type": "string",
+ "examples": ["University of Leicester"]
+ },
+ "examples": [["University of Leicester", "University Hospitals of Leicester"]]
+ },
+
+
+ },
+ "additionalProperties": true
+}
+
+```
+
+
+
+For this implementation there is no translation of the received query into fields used by the underlying DB, the data is stored within the metadata model format and all defined filters can act upon this model directly without translation.
+
+To keep the commands simple, the commands below are provided assuming no security has been added to your mongoDB installation. Adding basic security is highly recommended.
+
+```bash
+mongoimport --jsonArray --uri "mongodb://127.0.0.1:27017/beacon" --file data/datasets*.json --collection datasets
+mongoimport --jsonArray --uri "mongodb://127.0.0.1:27017/beacon" --file data/individual*.json --collection individuals
+```
+
+
+This loads the JSON files inside of the `data` folder into the MongoDB database.
+
+> You can also use `make load` as a convenience alias.
+
+
+### Light up the beacon
+
+#### Up the beacon
+
+Once the database is setup you can clone this repo onto your system and install all requirements.
+
+```
+cd EJP-RD-Beacon-in-a-Box
+pip install -r requirements.txt
+```
+
+You can then start the beacon with the following command:
+
+```bash
+python -m beacon
+```
+This command will print the logs and any errors to screen. Once you are happy that your installation is working then you can redirect the logs to a log file and restart the beacon server using a shell script or by disconnecting the process from the terminal window using "&" at the end of the command.
+
+```
+python -m beacon &> logfile.log &
+```
+
diff --git a/deploy/beacon-realm.json b/deploy/beacon-realm.json
new file mode 100644
index 0000000..3f69ea9
--- /dev/null
+++ b/deploy/beacon-realm.json
@@ -0,0 +1,1938 @@
+{
+ "id" : "Beacon",
+ "realm" : "Beacon",
+ "displayName" : "Beacon IdP",
+ "notBefore" : 0,
+ "revokeRefreshToken" : false,
+ "refreshTokenMaxReuse" : 0,
+ "accessTokenLifespan" : 300,
+ "accessTokenLifespanForImplicitFlow" : 900,
+ "ssoSessionIdleTimeout" : 1800,
+ "ssoSessionMaxLifespan" : 36000,
+ "ssoSessionIdleTimeoutRememberMe" : 0,
+ "ssoSessionMaxLifespanRememberMe" : 0,
+ "offlineSessionIdleTimeout" : 2592000,
+ "offlineSessionMaxLifespanEnabled" : false,
+ "offlineSessionMaxLifespan" : 5184000,
+ "clientSessionIdleTimeout" : 0,
+ "clientSessionMaxLifespan" : 0,
+ "clientOfflineSessionIdleTimeout" : 0,
+ "clientOfflineSessionMaxLifespan" : 0,
+ "accessCodeLifespan" : 60,
+ "accessCodeLifespanUserAction" : 300,
+ "accessCodeLifespanLogin" : 1800,
+ "actionTokenGeneratedByAdminLifespan" : 43200,
+ "actionTokenGeneratedByUserLifespan" : 300,
+ "enabled" : true,
+ "sslRequired" : "external",
+ "registrationAllowed" : false,
+ "registrationEmailAsUsername" : false,
+ "rememberMe" : false,
+ "verifyEmail" : false,
+ "loginWithEmailAllowed" : true,
+ "duplicateEmailsAllowed" : false,
+ "resetPasswordAllowed" : false,
+ "editUsernameAllowed" : false,
+ "bruteForceProtected" : false,
+ "permanentLockout" : false,
+ "maxFailureWaitSeconds" : 900,
+ "minimumQuickLoginWaitSeconds" : 60,
+ "waitIncrementSeconds" : 60,
+ "quickLoginCheckMilliSeconds" : 1000,
+ "maxDeltaTimeSeconds" : 43200,
+ "failureFactor" : 30,
+ "roles" : {
+ "realm" : [ {
+ "id" : "2df9f16e-1525-48e6-9b99-0025becfc001",
+ "name" : "offline_access",
+ "description" : "${role_offline-access}",
+ "composite" : false,
+ "clientRole" : false,
+ "containerId" : "Beacon",
+ "attributes" : { }
+ }, {
+ "id" : "fac1fd59-414a-4404-9dad-5c8966d14702",
+ "name" : "uma_authorization",
+ "description" : "${role_uma_authorization}",
+ "composite" : false,
+ "clientRole" : false,
+ "containerId" : "Beacon",
+ "attributes" : { }
+ } ],
+ "client" : {
+ "realm-management" : [ {
+ "id" : "a1f10106-92b5-4f83-8c8e-803302f06003",
+ "name" : "manage-clients",
+ "description" : "${role_manage-clients}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "f5aa5971-be11-4ca3-acdf-09404a58f846",
+ "attributes" : { }
+ }, {
+ "id" : "0bd797f8-c5a9-4d7f-bed6-ad4c104b185a",
+ "name" : "manage-users",
+ "description" : "${role_manage-users}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "f5aa5971-be11-4ca3-acdf-09404a58f846",
+ "attributes" : { }
+ }, {
+ "id" : "1c3cb9d9-9605-4940-9bbd-5c856c4bfd22",
+ "name" : "create-client",
+ "description" : "${role_create-client}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "f5aa5971-be11-4ca3-acdf-09404a58f846",
+ "attributes" : { }
+ }, {
+ "id" : "aac68b89-aeeb-450d-9f73-921fd98d0859",
+ "name" : "query-realms",
+ "description" : "${role_query-realms}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "f5aa5971-be11-4ca3-acdf-09404a58f846",
+ "attributes" : { }
+ }, {
+ "id" : "30edc3ef-56de-4261-9901-bd19ba13edfb",
+ "name" : "impersonation",
+ "description" : "${role_impersonation}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "f5aa5971-be11-4ca3-acdf-09404a58f846",
+ "attributes" : { }
+ }, {
+ "id" : "138e4838-9032-4dc6-80e9-cee6453830ff",
+ "name" : "manage-authorization",
+ "description" : "${role_manage-authorization}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "f5aa5971-be11-4ca3-acdf-09404a58f846",
+ "attributes" : { }
+ }, {
+ "id" : "8bb5fda6-3b4a-4024-8a54-6d3a9094c109",
+ "name" : "manage-events",
+ "description" : "${role_manage-events}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "f5aa5971-be11-4ca3-acdf-09404a58f846",
+ "attributes" : { }
+ }, {
+ "id" : "121804b4-c808-4690-bda6-342ea93da228",
+ "name" : "manage-identity-providers",
+ "description" : "${role_manage-identity-providers}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "f5aa5971-be11-4ca3-acdf-09404a58f846",
+ "attributes" : { }
+ }, {
+ "id" : "0537f9ce-24dc-4ac5-9bca-ce475c62a8f6",
+ "name" : "view-identity-providers",
+ "description" : "${role_view-identity-providers}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "f5aa5971-be11-4ca3-acdf-09404a58f846",
+ "attributes" : { }
+ }, {
+ "id" : "7a611915-c2f7-461a-966a-1197dbc1bf14",
+ "name" : "view-clients",
+ "description" : "${role_view-clients}",
+ "composite" : true,
+ "composites" : {
+ "client" : {
+ "realm-management" : [ "query-clients" ]
+ }
+ },
+ "clientRole" : true,
+ "containerId" : "f5aa5971-be11-4ca3-acdf-09404a58f846",
+ "attributes" : { }
+ }, {
+ "id" : "794db335-4616-41e0-ab5b-b72980fcbe85",
+ "name" : "query-groups",
+ "description" : "${role_query-groups}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "f5aa5971-be11-4ca3-acdf-09404a58f846",
+ "attributes" : { }
+ }, {
+ "id" : "955ede29-6fd3-4841-9afc-e70f1a2436dd",
+ "name" : "realm-admin",
+ "description" : "${role_realm-admin}",
+ "composite" : true,
+ "composites" : {
+ "client" : {
+ "realm-management" : [ "manage-clients", "manage-users", "create-client", "query-realms", "impersonation", "manage-authorization", "manage-events", "manage-identity-providers", "view-identity-providers", "view-clients", "query-groups", "view-authorization", "query-users", "view-realm", "view-events", "manage-realm", "view-users", "query-clients" ]
+ }
+ },
+ "clientRole" : true,
+ "containerId" : "f5aa5971-be11-4ca3-acdf-09404a58f846",
+ "attributes" : { }
+ }, {
+ "id" : "cab184fc-c654-4265-8e50-a32b65ce31e4",
+ "name" : "view-authorization",
+ "description" : "${role_view-authorization}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "f5aa5971-be11-4ca3-acdf-09404a58f846",
+ "attributes" : { }
+ }, {
+ "id" : "0e32f5b9-470d-4ceb-890e-fec18cbd4047",
+ "name" : "query-users",
+ "description" : "${role_query-users}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "f5aa5971-be11-4ca3-acdf-09404a58f846",
+ "attributes" : { }
+ }, {
+ "id" : "60add9d9-2579-49c1-85fe-02dba7f6eb9a",
+ "name" : "view-realm",
+ "description" : "${role_view-realm}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "f5aa5971-be11-4ca3-acdf-09404a58f846",
+ "attributes" : { }
+ }, {
+ "id" : "2644b82e-9c0c-4a43-a866-f3f1114b2ebd",
+ "name" : "view-events",
+ "description" : "${role_view-events}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "f5aa5971-be11-4ca3-acdf-09404a58f846",
+ "attributes" : { }
+ }, {
+ "id" : "7340893f-91d2-4236-921f-dd2f6a12e90a",
+ "name" : "manage-realm",
+ "description" : "${role_manage-realm}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "f5aa5971-be11-4ca3-acdf-09404a58f846",
+ "attributes" : { }
+ }, {
+ "id" : "de377fd2-965b-4051-85b3-917fc034d0dd",
+ "name" : "view-users",
+ "description" : "${role_view-users}",
+ "composite" : true,
+ "composites" : {
+ "client" : {
+ "realm-management" : [ "query-groups", "query-users" ]
+ }
+ },
+ "clientRole" : true,
+ "containerId" : "f5aa5971-be11-4ca3-acdf-09404a58f846",
+ "attributes" : { }
+ }, {
+ "id" : "b5c56d32-993d-4393-ae60-25ac65bba0d1",
+ "name" : "query-clients",
+ "description" : "${role_query-clients}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "f5aa5971-be11-4ca3-acdf-09404a58f846",
+ "attributes" : { }
+ } ],
+ "beacon" : [ {
+ "id" : "22e1ab24-7e8f-4ce6-98d0-3313d96f395b",
+ "name" : "uma_protection",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "8a753a23-230d-4003-b0aa-cdca03c57b8d",
+ "attributes" : { }
+ } ],
+ "permissions" : [ ],
+ "security-admin-console" : [ ],
+ "admin-cli" : [ ],
+ "account-console" : [ ],
+ "broker" : [ {
+ "id" : "94cd5ba4-4585-46a1-8e4a-7f289f7f2c8a",
+ "name" : "read-token",
+ "description" : "${role_read-token}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "61216acc-01da-4d8a-bd4d-b88c2b38686a",
+ "attributes" : { }
+ } ],
+ "account" : [ {
+ "id" : "a1a39879-ca59-4aa6-a4ae-cf7d836227ba",
+ "name" : "manage-account",
+ "description" : "${role_manage-account}",
+ "composite" : true,
+ "composites" : {
+ "client" : {
+ "account" : [ "manage-account-links" ]
+ }
+ },
+ "clientRole" : true,
+ "containerId" : "79fd7a63-8c74-44b5-91b2-6758c292930c",
+ "attributes" : { }
+ }, {
+ "id" : "9283fb4f-aa35-426a-82d1-c36421bbfa94",
+ "name" : "manage-consent",
+ "description" : "${role_manage-consent}",
+ "composite" : true,
+ "composites" : {
+ "client" : {
+ "account" : [ "view-consent" ]
+ }
+ },
+ "clientRole" : true,
+ "containerId" : "79fd7a63-8c74-44b5-91b2-6758c292930c",
+ "attributes" : { }
+ }, {
+ "id" : "539fcec1-7e97-4dee-b4cc-124c03358425",
+ "name" : "manage-account-links",
+ "description" : "${role_manage-account-links}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "79fd7a63-8c74-44b5-91b2-6758c292930c",
+ "attributes" : { }
+ }, {
+ "id" : "99c69a76-0af6-443d-a60d-1da2bdf352df",
+ "name" : "view-applications",
+ "description" : "${role_view-applications}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "79fd7a63-8c74-44b5-91b2-6758c292930c",
+ "attributes" : { }
+ }, {
+ "id" : "aadc367b-fde4-4cb7-81b1-0fb37689fbc3",
+ "name" : "view-consent",
+ "description" : "${role_view-consent}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "79fd7a63-8c74-44b5-91b2-6758c292930c",
+ "attributes" : { }
+ }, {
+ "id" : "89b3f80c-32d0-496c-a021-54b7344c6029",
+ "name" : "view-profile",
+ "description" : "${role_view-profile}",
+ "composite" : false,
+ "clientRole" : true,
+ "containerId" : "79fd7a63-8c74-44b5-91b2-6758c292930c",
+ "attributes" : { }
+ } ]
+ }
+ },
+ "groups" : [ {
+ "id" : "7c359d85-e9d0-4437-8b6d-90f347686da1",
+ "name" : "beacon-users",
+ "path" : "/beacon-users",
+ "attributes" : { },
+ "realmRoles" : [ ],
+ "clientRoles" : { },
+ "subGroups" : [ ]
+ } ],
+ "defaultRoles" : [ "offline_access", "uma_authorization" ],
+ "defaultGroups" : [ "/beacon-users" ],
+ "requiredCredentials" : [ "password" ],
+ "otpPolicyType" : "totp",
+ "otpPolicyAlgorithm" : "HmacSHA1",
+ "otpPolicyInitialCounter" : 0,
+ "otpPolicyDigits" : 6,
+ "otpPolicyLookAheadWindow" : 1,
+ "otpPolicyPeriod" : 30,
+ "otpSupportedApplications" : [ "FreeOTP", "Google Authenticator" ],
+ "webAuthnPolicyRpEntityName" : "keycloak",
+ "webAuthnPolicySignatureAlgorithms" : [ "ES256" ],
+ "webAuthnPolicyRpId" : "",
+ "webAuthnPolicyAttestationConveyancePreference" : "not specified",
+ "webAuthnPolicyAuthenticatorAttachment" : "not specified",
+ "webAuthnPolicyRequireResidentKey" : "not specified",
+ "webAuthnPolicyUserVerificationRequirement" : "not specified",
+ "webAuthnPolicyCreateTimeout" : 0,
+ "webAuthnPolicyAvoidSameAuthenticatorRegister" : false,
+ "webAuthnPolicyAcceptableAaguids" : [ ],
+ "webAuthnPolicyPasswordlessRpEntityName" : "keycloak",
+ "webAuthnPolicyPasswordlessSignatureAlgorithms" : [ "ES256" ],
+ "webAuthnPolicyPasswordlessRpId" : "",
+ "webAuthnPolicyPasswordlessAttestationConveyancePreference" : "not specified",
+ "webAuthnPolicyPasswordlessAuthenticatorAttachment" : "not specified",
+ "webAuthnPolicyPasswordlessRequireResidentKey" : "not specified",
+ "webAuthnPolicyPasswordlessUserVerificationRequirement" : "not specified",
+ "webAuthnPolicyPasswordlessCreateTimeout" : 0,
+ "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister" : false,
+ "webAuthnPolicyPasswordlessAcceptableAaguids" : [ ],
+ "users" : [ {
+ "id" : "47eff1b1-7621-4570-a0bb-01a719fba0a2",
+ "createdTimestamp" : 1598453205967,
+ "username" : "jane",
+ "enabled" : true,
+ "totp" : false,
+ "emailVerified" : false,
+ "firstName" : "Jane",
+ "lastName" : "Smith",
+ "email" : "jane.smith@beacon.ga4gh",
+ "credentials" : [ {
+ "id" : "7e296b71-a7c0-47de-91fb-d33f014f99c8",
+ "type" : "password",
+ "createdDate" : 1598453835625,
+ "secretData" : "{\"value\":\"BIJ/DUkfa56KUsZQFU/C8RLbIv1C8sJ74HJcQv2A+iPSuMl0UHULWtkIeXfHPiOU+od/K0N1ugYxGqlfReHrwg==\",\"salt\":\"lDP6qAYsN+bZCFAn3trSwA==\"}",
+ "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\"}"
+ } ],
+ "disableableCredentialTypes" : [ ],
+ "requiredActions" : [ ],
+ "realmRoles" : [ "offline_access", "uma_authorization" ],
+ "clientRoles" : {
+ "account" : [ "manage-account", "view-profile" ]
+ },
+ "notBefore" : 0,
+ "groups" : [ "/beacon-users" ]
+ }, {
+ "id" : "8718f980-47bc-4be6-9390-a01343eed37d",
+ "createdTimestamp" : 1598453171030,
+ "username" : "john",
+ "enabled" : true,
+ "totp" : false,
+ "emailVerified" : false,
+ "firstName" : "John",
+ "lastName" : "Smith",
+ "email" : "john.smith@beacon.ga4gh",
+ "credentials" : [ {
+ "id" : "ac14b184-797f-4f85-bbb7-582f2f3f5727",
+ "type" : "password",
+ "createdDate" : 1598453805633,
+ "secretData" : "{\"value\":\"X3rvS//rfkmMAsUN7z6EhELbz6WvFXG/SNjMm8k4apa+PWiM9HhK1XcwlbKz6kSxT53MEph3LDU88v1BSxm/eg==\",\"salt\":\"5Eu8VQejJtAi9t1jHd5KLA==\"}",
+ "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\"}"
+ } ],
+ "disableableCredentialTypes" : [ ],
+ "requiredActions" : [ ],
+ "realmRoles" : [ "offline_access", "uma_authorization" ],
+ "clientRoles" : {
+ "account" : [ "manage-account", "view-profile" ]
+ },
+ "notBefore" : 0,
+ "groups" : [ "/beacon-users" ]
+ } ],
+ "scopeMappings" : [ {
+ "clientScope" : "offline_access",
+ "roles" : [ "offline_access" ]
+ } ],
+ "clientScopeMappings" : {
+ "account" : [ {
+ "client" : "account-console",
+ "roles" : [ "manage-account" ]
+ } ]
+ },
+ "clients" : [ {
+ "id" : "79fd7a63-8c74-44b5-91b2-6758c292930c",
+ "clientId" : "account",
+ "name" : "${client_account}",
+ "rootUrl" : "${authBaseUrl}",
+ "baseUrl" : "/realms/Beacon/account/",
+ "surrogateAuthRequired" : false,
+ "enabled" : true,
+ "alwaysDisplayInConsole" : false,
+ "clientAuthenticatorType" : "client-secret",
+ "secret" : "**********",
+ "defaultRoles" : [ "manage-account", "view-profile" ],
+ "redirectUris" : [ "/realms/Beacon/account/*" ],
+ "webOrigins" : [ ],
+ "notBefore" : 0,
+ "bearerOnly" : false,
+ "consentRequired" : false,
+ "standardFlowEnabled" : true,
+ "implicitFlowEnabled" : false,
+ "directAccessGrantsEnabled" : false,
+ "serviceAccountsEnabled" : false,
+ "publicClient" : false,
+ "frontchannelLogout" : false,
+ "protocol" : "openid-connect",
+ "attributes" : { },
+ "authenticationFlowBindingOverrides" : { },
+ "fullScopeAllowed" : false,
+ "nodeReRegistrationTimeout" : 0,
+ "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ],
+ "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+ }, {
+ "id" : "3cf6f41f-35f0-42a2-bce8-a054ef16ad9b",
+ "clientId" : "account-console",
+ "name" : "${client_account-console}",
+ "rootUrl" : "${authBaseUrl}",
+ "baseUrl" : "/realms/Beacon/account/",
+ "surrogateAuthRequired" : false,
+ "enabled" : true,
+ "alwaysDisplayInConsole" : false,
+ "clientAuthenticatorType" : "client-secret",
+ "secret" : "**********",
+ "redirectUris" : [ "/realms/Beacon/account/*" ],
+ "webOrigins" : [ ],
+ "notBefore" : 0,
+ "bearerOnly" : false,
+ "consentRequired" : false,
+ "standardFlowEnabled" : true,
+ "implicitFlowEnabled" : false,
+ "directAccessGrantsEnabled" : false,
+ "serviceAccountsEnabled" : false,
+ "publicClient" : true,
+ "frontchannelLogout" : false,
+ "protocol" : "openid-connect",
+ "attributes" : {
+ "pkce.code.challenge.method" : "S256"
+ },
+ "authenticationFlowBindingOverrides" : { },
+ "fullScopeAllowed" : false,
+ "nodeReRegistrationTimeout" : 0,
+ "protocolMappers" : [ {
+ "id" : "a511954d-5d75-492d-bb7a-f22a185eea67",
+ "name" : "audience resolve",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-audience-resolve-mapper",
+ "consentRequired" : false,
+ "config" : { }
+ } ],
+ "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ],
+ "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+ }, {
+ "id" : "2972da43-8cb0-4568-aca8-997a60f70e3d",
+ "clientId" : "admin-cli",
+ "name" : "${client_admin-cli}",
+ "surrogateAuthRequired" : false,
+ "enabled" : true,
+ "alwaysDisplayInConsole" : false,
+ "clientAuthenticatorType" : "client-secret",
+ "secret" : "**********",
+ "redirectUris" : [ ],
+ "webOrigins" : [ ],
+ "notBefore" : 0,
+ "bearerOnly" : false,
+ "consentRequired" : false,
+ "standardFlowEnabled" : false,
+ "implicitFlowEnabled" : false,
+ "directAccessGrantsEnabled" : true,
+ "serviceAccountsEnabled" : false,
+ "publicClient" : true,
+ "frontchannelLogout" : false,
+ "protocol" : "openid-connect",
+ "attributes" : { },
+ "authenticationFlowBindingOverrides" : { },
+ "fullScopeAllowed" : false,
+ "nodeReRegistrationTimeout" : 0,
+ "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ],
+ "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+ }, {
+ "id" : "8a753a23-230d-4003-b0aa-cdca03c57b8d",
+ "clientId" : "beacon",
+ "name" : "Beacon",
+ "description" : "Demo Beacon",
+ "baseUrl" : "http://beacon:5050",
+ "surrogateAuthRequired" : false,
+ "enabled" : true,
+ "alwaysDisplayInConsole" : false,
+ "clientAuthenticatorType" : "client-secret",
+ "secret" : "b26ca0f9-1137-4bee-b453-ee51eefbe7ba",
+ "redirectUris" : [ "http://beacon:5050/*" ],
+ "webOrigins" : [ ],
+ "notBefore" : 0,
+ "bearerOnly" : false,
+ "consentRequired" : false,
+ "standardFlowEnabled" : true,
+ "implicitFlowEnabled" : false,
+ "directAccessGrantsEnabled" : true,
+ "serviceAccountsEnabled" : false,
+ "publicClient" : false,
+ "frontchannelLogout" : false,
+ "protocol" : "openid-connect",
+ "attributes" : {
+ "saml.assertion.signature" : "false",
+ "saml.force.post.binding" : "false",
+ "saml.multivalued.roles" : "false",
+ "saml.encrypt" : "false",
+ "saml.server.signature" : "false",
+ "saml.server.signature.keyinfo.ext" : "false",
+ "exclude.session.state.from.auth.response" : "false",
+ "saml_force_name_id_format" : "false",
+ "saml.client.signature" : "false",
+ "tls.client.certificate.bound.access.tokens" : "false",
+ "saml.authnstatement" : "false",
+ "display.on.consent.screen" : "false",
+ "saml.onetimeuse.condition" : "false"
+ },
+ "authenticationFlowBindingOverrides" : { },
+ "fullScopeAllowed" : true,
+ "nodeReRegistrationTimeout" : -1,
+ "protocolMappers" : [ {
+ "id" : "6d5cf9b1-90f3-4984-a654-17b0bf16975a",
+ "name" : "Client Host",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "user.session.note" : "clientHost",
+ "userinfo.token.claim" : "true",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "clientHost",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "5e4d9971-efdb-4bab-ba8a-10ea9b95d716",
+ "name" : "Client ID",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "user.session.note" : "clientId",
+ "userinfo.token.claim" : "true",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "clientId",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "de72c9ab-d9b5-48a8-936f-801120d2a449",
+ "name" : "given name",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-property-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "firstName",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "given_name",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "751c9280-6c3e-4f3c-a014-4573dbb4bd1c",
+ "name" : "family name",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-property-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "lastName",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "family_name",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "71bb92a2-9157-4393-8109-32fb0c9b4925",
+ "name" : "profile",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "profile",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "profile",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "a7eea6fb-85d6-4fe5-a2e1-c1fa9a33e5c2",
+ "name" : "picture",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "picture",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "picture",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "40c90763-a47e-4ae2-9818-1598f4a546d7",
+ "name" : "email",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-property-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "email",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "email",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "fb04c2ad-c08a-4028-b3a7-996a6269b274",
+ "name" : "groups",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-realm-role-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "multivalued" : "true",
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "foo",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "groups",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "49e41be7-9faf-4016-be3e-5c6c862001e6",
+ "name" : "Client IP Address",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usersessionmodel-note-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "user.session.note" : "clientAddress",
+ "userinfo.token.claim" : "true",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "clientAddress",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "9efffa4e-dcfd-4177-b300-ba1ad534d799",
+ "name" : "nickname",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "nickname",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "nickname",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "4d664844-ca38-4a96-906e-f9fe3fda5b2d",
+ "name" : "username",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-property-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "username",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "preferred_username",
+ "jsonType.label" : "String"
+ }
+ } ],
+ "defaultClientScopes" : [ "role_list", "profile", "microprofile-jwt", "email" ],
+ "optionalClientScopes" : [ ]
+ }, {
+ "id" : "61216acc-01da-4d8a-bd4d-b88c2b38686a",
+ "clientId" : "broker",
+ "name" : "${client_broker}",
+ "surrogateAuthRequired" : false,
+ "enabled" : true,
+ "alwaysDisplayInConsole" : false,
+ "clientAuthenticatorType" : "client-secret",
+ "secret" : "**********",
+ "redirectUris" : [ ],
+ "webOrigins" : [ ],
+ "notBefore" : 0,
+ "bearerOnly" : false,
+ "consentRequired" : false,
+ "standardFlowEnabled" : true,
+ "implicitFlowEnabled" : false,
+ "directAccessGrantsEnabled" : false,
+ "serviceAccountsEnabled" : false,
+ "publicClient" : false,
+ "frontchannelLogout" : false,
+ "protocol" : "openid-connect",
+ "attributes" : { },
+ "authenticationFlowBindingOverrides" : { },
+ "fullScopeAllowed" : false,
+ "nodeReRegistrationTimeout" : 0,
+ "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ],
+ "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+ }, {
+ "id" : "ef278d04-53c6-4b4f-ae93-0aec719f84dd",
+ "clientId" : "permissions",
+ "name" : "Beacon Permissions",
+ "adminUrl" : "http://beacon-permissions",
+ "surrogateAuthRequired" : false,
+ "enabled" : true,
+ "alwaysDisplayInConsole" : false,
+ "clientAuthenticatorType" : "client-secret",
+ "secret" : "c0285717-1bfb-4b32-b01d-d663470ce7c4",
+ "redirectUris" : [ ],
+ "webOrigins" : [ ],
+ "notBefore" : 0,
+ "bearerOnly" : true,
+ "consentRequired" : false,
+ "standardFlowEnabled" : true,
+ "implicitFlowEnabled" : false,
+ "directAccessGrantsEnabled" : true,
+ "serviceAccountsEnabled" : false,
+ "publicClient" : false,
+ "frontchannelLogout" : false,
+ "protocol" : "openid-connect",
+ "attributes" : {
+ "saml.assertion.signature" : "false",
+ "saml.force.post.binding" : "false",
+ "saml.multivalued.roles" : "false",
+ "saml.encrypt" : "false",
+ "saml.server.signature" : "false",
+ "saml.server.signature.keyinfo.ext" : "false",
+ "exclude.session.state.from.auth.response" : "false",
+ "saml_force_name_id_format" : "false",
+ "saml.client.signature" : "false",
+ "tls.client.certificate.bound.access.tokens" : "false",
+ "saml.authnstatement" : "false",
+ "display.on.consent.screen" : "false",
+ "saml.onetimeuse.condition" : "false"
+ },
+ "authenticationFlowBindingOverrides" : { },
+ "fullScopeAllowed" : true,
+ "nodeReRegistrationTimeout" : -1,
+ "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ],
+ "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+ }, {
+ "id" : "f5aa5971-be11-4ca3-acdf-09404a58f846",
+ "clientId" : "realm-management",
+ "name" : "${client_realm-management}",
+ "surrogateAuthRequired" : false,
+ "enabled" : true,
+ "alwaysDisplayInConsole" : false,
+ "clientAuthenticatorType" : "client-secret",
+ "secret" : "**********",
+ "redirectUris" : [ ],
+ "webOrigins" : [ ],
+ "notBefore" : 0,
+ "bearerOnly" : true,
+ "consentRequired" : false,
+ "standardFlowEnabled" : true,
+ "implicitFlowEnabled" : false,
+ "directAccessGrantsEnabled" : false,
+ "serviceAccountsEnabled" : false,
+ "publicClient" : false,
+ "frontchannelLogout" : false,
+ "protocol" : "openid-connect",
+ "attributes" : { },
+ "authenticationFlowBindingOverrides" : { },
+ "fullScopeAllowed" : false,
+ "nodeReRegistrationTimeout" : 0,
+ "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ],
+ "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+ }, {
+ "id" : "0f1f4a6b-4f48-406e-8ec8-7b5329403a6e",
+ "clientId" : "security-admin-console",
+ "name" : "${client_security-admin-console}",
+ "rootUrl" : "${authAdminUrl}",
+ "baseUrl" : "/admin/Beacon/console/",
+ "surrogateAuthRequired" : false,
+ "enabled" : true,
+ "alwaysDisplayInConsole" : false,
+ "clientAuthenticatorType" : "client-secret",
+ "secret" : "**********",
+ "redirectUris" : [ "/admin/Beacon/console/*" ],
+ "webOrigins" : [ "+" ],
+ "notBefore" : 0,
+ "bearerOnly" : false,
+ "consentRequired" : false,
+ "standardFlowEnabled" : true,
+ "implicitFlowEnabled" : false,
+ "directAccessGrantsEnabled" : false,
+ "serviceAccountsEnabled" : false,
+ "publicClient" : true,
+ "frontchannelLogout" : false,
+ "protocol" : "openid-connect",
+ "attributes" : {
+ "pkce.code.challenge.method" : "S256"
+ },
+ "authenticationFlowBindingOverrides" : { },
+ "fullScopeAllowed" : false,
+ "nodeReRegistrationTimeout" : 0,
+ "protocolMappers" : [ {
+ "id" : "e1c5d474-7edc-4ccb-9d59-13df4f1d5dc0",
+ "name" : "locale",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "locale",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "locale",
+ "jsonType.label" : "String"
+ }
+ } ],
+ "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ],
+ "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ]
+ } ],
+ "clientScopes" : [ {
+ "id" : "435ee055-d511-40e2-a4cd-43ee57d7b244",
+ "name" : "offline_access",
+ "description" : "OpenID Connect built-in scope: offline_access",
+ "protocol" : "openid-connect",
+ "attributes" : {
+ "consent.screen.text" : "${offlineAccessScopeConsentText}",
+ "display.on.consent.screen" : "true"
+ }
+ }, {
+ "id" : "d5cbff9b-1e97-444d-b772-eae9c283788c",
+ "name" : "role_list",
+ "description" : "SAML role list",
+ "protocol" : "saml",
+ "attributes" : {
+ "consent.screen.text" : "${samlRoleListScopeConsentText}",
+ "display.on.consent.screen" : "true"
+ },
+ "protocolMappers" : [ {
+ "id" : "b0a7f711-315f-4311-9d49-279392aa9ce0",
+ "name" : "role list",
+ "protocol" : "saml",
+ "protocolMapper" : "saml-role-list-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "single" : "false",
+ "attribute.nameformat" : "Basic",
+ "attribute.name" : "Role"
+ }
+ } ]
+ }, {
+ "id" : "53d0f60a-9b81-4250-ad44-de7afc4bae90",
+ "name" : "profile",
+ "description" : "OpenID Connect built-in scope: profile",
+ "protocol" : "openid-connect",
+ "attributes" : {
+ "include.in.token.scope" : "true",
+ "display.on.consent.screen" : "true",
+ "consent.screen.text" : "${profileScopeConsentText}"
+ },
+ "protocolMappers" : [ {
+ "id" : "62019f78-a48e-4ad1-bb22-5036ddc7f329",
+ "name" : "gender",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "gender",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "gender",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "230fc610-50a7-4e3b-8438-e0c962cef686",
+ "name" : "nickname",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "nickname",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "nickname",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "b1f0d13a-e1bf-4223-b819-041d5fa7ac93",
+ "name" : "username",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-property-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "username",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "preferred_username",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "e2300d7d-6e86-4fb5-82c1-3e447f7e2ed0",
+ "name" : "full name",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-full-name-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "userinfo.token.claim" : "true"
+ }
+ }, {
+ "id" : "1754c79c-096b-4709-b472-5b1af0bb9826",
+ "name" : "website",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "website",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "website",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "8d6a602c-7a2b-4974-84a9-6be65b805812",
+ "name" : "family name",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-property-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "lastName",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "family_name",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "8a9a6c4b-7307-42cb-83d7-bafd24cf3bf8",
+ "name" : "picture",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "picture",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "picture",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "5ce0b39c-6d26-4a5f-bbbd-370f7463ba7d",
+ "name" : "zoneinfo",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "zoneinfo",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "zoneinfo",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "27427bea-0fce-4951-ace6-511028d71bc5",
+ "name" : "updated at",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "updatedAt",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "updated_at",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "fca33576-a310-4fc1-9da6-3b6b719c144e",
+ "name" : "locale",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "locale",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "locale",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "93f997a6-509e-471d-9b74-6bdcb614e6fa",
+ "name" : "birthdate",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "birthdate",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "birthdate",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "21eaa433-da47-4835-8c32-16ad1215aa5f",
+ "name" : "middle name",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "middleName",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "middle_name",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "f884e878-1808-4786-ac1c-c548e847f0e4",
+ "name" : "profile",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "profile",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "profile",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "56471621-4c26-44bd-856f-92390502e30a",
+ "name" : "given name",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-property-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "firstName",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "given_name",
+ "jsonType.label" : "String"
+ }
+ } ]
+ }, {
+ "id" : "c85970c9-0b07-428e-b6ad-39f85e35b9a0",
+ "name" : "email",
+ "description" : "OpenID Connect built-in scope: email",
+ "protocol" : "openid-connect",
+ "attributes" : {
+ "include.in.token.scope" : "true",
+ "display.on.consent.screen" : "true",
+ "consent.screen.text" : "${emailScopeConsentText}"
+ },
+ "protocolMappers" : [ {
+ "id" : "b212389d-bd7b-495b-aa8b-5548fb169301",
+ "name" : "email verified",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-property-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "emailVerified",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "email_verified",
+ "jsonType.label" : "boolean"
+ }
+ }, {
+ "id" : "1dbb047e-94d4-490b-b1f2-4eb0d58683a8",
+ "name" : "email",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-property-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "email",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "email",
+ "jsonType.label" : "String"
+ }
+ } ]
+ }, {
+ "id" : "33ca96d2-6623-471e-ada7-64e8d32b0a82",
+ "name" : "address",
+ "description" : "OpenID Connect built-in scope: address",
+ "protocol" : "openid-connect",
+ "attributes" : {
+ "include.in.token.scope" : "true",
+ "display.on.consent.screen" : "true",
+ "consent.screen.text" : "${addressScopeConsentText}"
+ },
+ "protocolMappers" : [ {
+ "id" : "76fece78-a315-420a-a7ba-73d9cd7bf407",
+ "name" : "address",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-address-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "user.attribute.formatted" : "formatted",
+ "user.attribute.country" : "country",
+ "user.attribute.postal_code" : "postal_code",
+ "userinfo.token.claim" : "true",
+ "user.attribute.street" : "street",
+ "id.token.claim" : "true",
+ "user.attribute.region" : "region",
+ "access.token.claim" : "true",
+ "user.attribute.locality" : "locality"
+ }
+ } ]
+ }, {
+ "id" : "f60f8df2-69a3-4bef-a92f-2414ce41dc97",
+ "name" : "phone",
+ "description" : "OpenID Connect built-in scope: phone",
+ "protocol" : "openid-connect",
+ "attributes" : {
+ "include.in.token.scope" : "true",
+ "display.on.consent.screen" : "true",
+ "consent.screen.text" : "${phoneScopeConsentText}"
+ },
+ "protocolMappers" : [ {
+ "id" : "002e7fdf-1b16-44d9-94fd-cb48b3935f08",
+ "name" : "phone number",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "phoneNumber",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "phone_number",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "5865166d-9a6f-4135-89df-1c2b3c211f78",
+ "name" : "phone number verified",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-attribute-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "phoneNumberVerified",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "phone_number_verified",
+ "jsonType.label" : "boolean"
+ }
+ } ]
+ }, {
+ "id" : "f68013ac-4d64-4d8b-af14-b0f057598707",
+ "name" : "roles",
+ "description" : "OpenID Connect scope for add user roles to the access token",
+ "protocol" : "openid-connect",
+ "attributes" : {
+ "include.in.token.scope" : "false",
+ "display.on.consent.screen" : "true",
+ "consent.screen.text" : "${rolesScopeConsentText}"
+ },
+ "protocolMappers" : [ {
+ "id" : "72f6d9d8-4988-4117-80ee-a29ab6d25c44",
+ "name" : "audience resolve",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-audience-resolve-mapper",
+ "consentRequired" : false,
+ "config" : { }
+ }, {
+ "id" : "f64a33fe-70ea-4ab2-9b7c-651537b687f4",
+ "name" : "client roles",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-client-role-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "user.attribute" : "foo",
+ "access.token.claim" : "true",
+ "claim.name" : "resource_access.${client_id}.roles",
+ "jsonType.label" : "String",
+ "multivalued" : "true"
+ }
+ }, {
+ "id" : "801a390b-7f0b-406f-9428-4b6477f9a7be",
+ "name" : "realm roles",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-realm-role-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "user.attribute" : "foo",
+ "access.token.claim" : "true",
+ "claim.name" : "realm_access.roles",
+ "jsonType.label" : "String",
+ "multivalued" : "true"
+ }
+ } ]
+ }, {
+ "id" : "73a42667-6266-4367-b907-00369d54ad2b",
+ "name" : "web-origins",
+ "description" : "OpenID Connect scope for add allowed web origins to the access token",
+ "protocol" : "openid-connect",
+ "attributes" : {
+ "include.in.token.scope" : "false",
+ "display.on.consent.screen" : "false",
+ "consent.screen.text" : ""
+ },
+ "protocolMappers" : [ {
+ "id" : "9355ebcb-d5e8-4876-b09c-141960318070",
+ "name" : "allowed web origins",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-allowed-origins-mapper",
+ "consentRequired" : false,
+ "config" : { }
+ } ]
+ }, {
+ "id" : "a3bd3167-f7cf-4330-ab73-4c1115c1647e",
+ "name" : "microprofile-jwt",
+ "description" : "Microprofile - JWT built-in scope",
+ "protocol" : "openid-connect",
+ "attributes" : {
+ "include.in.token.scope" : "true",
+ "display.on.consent.screen" : "false"
+ },
+ "protocolMappers" : [ {
+ "id" : "aae18ed9-4b47-427f-9c72-78b158373b3b",
+ "name" : "groups",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-realm-role-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "multivalued" : "true",
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "foo",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "groups",
+ "jsonType.label" : "String"
+ }
+ }, {
+ "id" : "f3a6dbf0-6756-4271-92c7-a0609307f12c",
+ "name" : "upn",
+ "protocol" : "openid-connect",
+ "protocolMapper" : "oidc-usermodel-property-mapper",
+ "consentRequired" : false,
+ "config" : {
+ "userinfo.token.claim" : "true",
+ "user.attribute" : "username",
+ "id.token.claim" : "true",
+ "access.token.claim" : "true",
+ "claim.name" : "upn",
+ "jsonType.label" : "String"
+ }
+ } ]
+ } ],
+ "defaultDefaultClientScopes" : [ "role_list", "profile", "email", "roles", "web-origins" ],
+ "defaultOptionalClientScopes" : [ "offline_access", "address", "phone", "microprofile-jwt" ],
+ "browserSecurityHeaders" : {
+ "contentSecurityPolicyReportOnly" : "",
+ "xContentTypeOptions" : "nosniff",
+ "xRobotsTag" : "none",
+ "xFrameOptions" : "SAMEORIGIN",
+ "contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';",
+ "xXSSProtection" : "1; mode=block",
+ "strictTransportSecurity" : "max-age=31536000; includeSubDomains"
+ },
+ "smtpServer" : { },
+ "eventsEnabled" : false,
+ "eventsListeners" : [ "jboss-logging" ],
+ "enabledEventTypes" : [ ],
+ "adminEventsEnabled" : false,
+ "adminEventsDetailsEnabled" : false,
+ "components" : {
+ "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ {
+ "id" : "811153f0-3d4a-42ae-93ef-b26ac06c94aa",
+ "name" : "Max Clients Limit",
+ "providerId" : "max-clients",
+ "subType" : "anonymous",
+ "subComponents" : { },
+ "config" : {
+ "max-clients" : [ "200" ]
+ }
+ }, {
+ "id" : "63d2fcfe-a8f1-4393-8f5a-d5eea356d778",
+ "name" : "Trusted Hosts",
+ "providerId" : "trusted-hosts",
+ "subType" : "anonymous",
+ "subComponents" : { },
+ "config" : {
+ "host-sending-registration-request-must-match" : [ "true" ],
+ "client-uris-must-match" : [ "true" ]
+ }
+ }, {
+ "id" : "8bb81a99-83e2-4968-9963-eb70b0fe753c",
+ "name" : "Allowed Client Scopes",
+ "providerId" : "allowed-client-templates",
+ "subType" : "anonymous",
+ "subComponents" : { },
+ "config" : {
+ "allow-default-scopes" : [ "true" ]
+ }
+ }, {
+ "id" : "816adcb3-0414-47dd-b231-a45a095edc81",
+ "name" : "Consent Required",
+ "providerId" : "consent-required",
+ "subType" : "anonymous",
+ "subComponents" : { },
+ "config" : { }
+ }, {
+ "id" : "3f5888e8-bc23-4f1e-a215-43c59fa0a713",
+ "name" : "Full Scope Disabled",
+ "providerId" : "scope",
+ "subType" : "anonymous",
+ "subComponents" : { },
+ "config" : { }
+ }, {
+ "id" : "1fea56dc-6a52-4d47-8058-6bf4c5a28f4b",
+ "name" : "Allowed Protocol Mapper Types",
+ "providerId" : "allowed-protocol-mappers",
+ "subType" : "anonymous",
+ "subComponents" : { },
+ "config" : {
+ "allowed-protocol-mapper-types" : [ "saml-user-attribute-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "oidc-address-mapper", "oidc-usermodel-property-mapper", "saml-user-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper" ]
+ }
+ }, {
+ "id" : "f3413e70-66b0-4ca4-840e-ad22598416cc",
+ "name" : "Allowed Client Scopes",
+ "providerId" : "allowed-client-templates",
+ "subType" : "authenticated",
+ "subComponents" : { },
+ "config" : {
+ "allow-default-scopes" : [ "true" ]
+ }
+ }, {
+ "id" : "c88d027d-355d-4ae7-a5ff-1f4a456f6e86",
+ "name" : "Allowed Protocol Mapper Types",
+ "providerId" : "allowed-protocol-mappers",
+ "subType" : "authenticated",
+ "subComponents" : { },
+ "config" : {
+ "allowed-protocol-mapper-types" : [ "saml-user-attribute-mapper", "saml-user-property-mapper", "oidc-full-name-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-usermodel-property-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper", "oidc-address-mapper" ]
+ }
+ } ],
+ "org.keycloak.keys.KeyProvider" : [ {
+ "id" : "d3a46f12-da7c-4960-b429-7a82b5c23d02",
+ "name" : "aes-generated",
+ "providerId" : "aes-generated",
+ "subComponents" : { },
+ "config" : {
+ "kid" : [ "24d4bf93-2344-46d3-b04e-8d98891a81d6" ],
+ "secret" : [ "dWZJQ_bbbYqaYqITXzvngg" ],
+ "priority" : [ "100" ]
+ }
+ }, {
+ "id" : "26b721b0-41fc-48d0-b57f-5bab8f968ae8",
+ "name" : "hmac-generated",
+ "providerId" : "hmac-generated",
+ "subComponents" : { },
+ "config" : {
+ "kid" : [ "568d15ee-15e6-403a-8bd8-1c137d69d002" ],
+ "secret" : [ "T5WZ51KmfQ7JhhcsbG1kSJMCGgmsftnOYv8m8ZilCYnXtNuZn0lu68U-uVrrDJTUFv2uiSisapZaysxRdEtGSw" ],
+ "priority" : [ "100" ],
+ "algorithm" : [ "HS256" ]
+ }
+ }, {
+ "id" : "0660a039-4702-4765-a534-ec339b6afcc9",
+ "name" : "rsa-generated",
+ "providerId" : "rsa-generated",
+ "subComponents" : { },
+ "config" : {
+ "privateKey" : [ "MIIEpQIBAAKCAQEAp8Ratd6KfNju4CmwsP/vlSMIVu/QtIy6gsTKXIf1/0YGslwMCsISBRCQ7TLhUnMmoWhSXBW/4VQTLNUamMKDsKLOeR5UJRQOa/PNZexP5tqBlsilkkvy3tW0UzvqxM5rJr3J3gOwuRcxLG3v/uBtSUN556OICaRZPMPEgbt9bDed8PhoSLNlfrqQAwDboNOifK8Di774hH+r0vd3yr1e3dqXXzMJpW4CN6undyP1ZC+8+BD2OM39vJJ8MCe9KXGSzMXH1raOCa9PPHLITjOf1Cz6fVpKbGLQKOdnC2gima+D9w2pyNjsmyssQJocyw8hnk2R3xzqM3M+A2DLaOSQOwIDAQABAoIBAQCCEKfm4i5p1mFz5r52qyWacPuRMwGSSJx8r4bXsAzWqPqeIuCvIoCH7qz9SHoJyv6DGnbnr3EAh4cKNfkVv5ALTF1Y51uDF4aKyQxP3aKgrnzTYqGCx2D2w6W29ffwNrw539/2QNQs2z8jW+Q5rNLtfuOu40ifeQw6IOhjT/FQCJkBJct9iulUw1gNNSk+9mVwOZXIhbDFK2eZyBUPrNadrGgOeE3attkfUXI0pQCg7bV3Ee+y+CK6rJ4CXQPdcYviHGVc1oJN9eYmDGDr1o0USGS8lOmrJTy6+QXZqpi38aZVeBTG0ywrsZ4123o4UWcRrsLIQLPVfkDbykXW/BZRAoGBANOLv5QlIv5BlTZJSqN94Hb9FuMt4P2dtJKErkdv0yH/NHacsd+bDhjenu4sgX+UZ0J0URo8GZG6Nh4nuRoP5tPgG1nDAxSgSvzQuVagocm190f2YTJPs6cpZ9TJJMf6xNcC7W9pN6BXby7AQ4nYC/OQYr1V3nkLDn/h0F9ZWTZpAoGBAMsFfe7m0CkqnGkgEorEVYi6Lnl8mXSPsoW2dop/8C/Osm7sHEg9tpRFttXUOrYnQmxAd/izrtX0SV5qfGGEQohenAhdMWUqKwTQOrI+uIWx1bL8YaLkPmEmm7UCwsuYh/XZhpLIwMxp9REMWAt8XPvYcyi0LKFs6ANvZdviJeUDAoGBAJgcYIERwvu4BKaoRLcSiBiHG7H3B1TV1UWVigtr6REFBKBVQ8FZKOXRDc6MygEGoMk0Ai0vEeOrVcaRIZQP4xZuirwccVafe8wV+W7EyhDUex6Plowqqy+Dollq2LvDIU7JmBkIOytcM2IWdXnkk5NrOtSRrgqzXJWvtbkZ8gAhAoGBAJ7+Ag2h/MsAb9V0JJFACKw3AkZp6dN65ZgJuPPmFbea6+oqRkvc6KtdnT4AIqqcPEyCgHHoZbdwxDSIuDe2WFRro055jUFosJ/oYs9Mhz1Mc8rkE6J5lNCIZ9BuBRdksLU8UUOKrFJpeF6NiDYWgstIS4dI8trIazqlduOoS3z5AoGACoeJIndd1Ukkg2N4NnzQb7Yal+0q39mdQpIWe51gvIh9x+LMm+2eJaTm5vSFNGSO5MpCLUl2LNKwGeWd5cjO7muTAtFGn7vy+Z7osJi5XfwgnTlpt786zSE0Fu3AM6sLqPkJy8XXQuOZOaQB6sNa9jXsffpWdwBZ6dF1R3aN+T8=" ],
+ "certificate" : [ "MIICmzCCAYMCBgF0KzkkAjANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZCZWFjb24wHhcNMjAwODI2MTQ0MTM5WhcNMzAwODI2MTQ0MzE5WjARMQ8wDQYDVQQDDAZCZWFjb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCnxFq13op82O7gKbCw/++VIwhW79C0jLqCxMpch/X/RgayXAwKwhIFEJDtMuFScyahaFJcFb/hVBMs1RqYwoOwos55HlQlFA5r881l7E/m2oGWyKWSS/Le1bRTO+rEzmsmvcneA7C5FzEsbe/+4G1JQ3nno4gJpFk8w8SBu31sN53w+GhIs2V+upADANug06J8rwOLvviEf6vS93fKvV7d2pdfMwmlbgI3q6d3I/VkL7z4EPY4zf28knwwJ70pcZLMxcfWto4Jr088cshOM5/ULPp9WkpsYtAo52cLaCKZr4P3DanI2OybKyxAmhzLDyGeTZHfHOozcz4DYMto5JA7AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAG3K//oLZumV6ZDTAEfbVVh6W4i3YO+mosZuxRIDr0b7bN9dlp/xb8jtIFk2+/Hoie0SogLyCvlAAeokJb9+TIZ4CMUBRo4fMpTqSiTUr9EMj9rpG9pM3vho3EBnnV5MeUZPBj5G1JomYz/gBjrXBywuxHIoKa6eYGnXrirpUXTSEAPpm5fvvhoMz/fFAW/1GYFczAqsaPwCjD1nrBJ6lRywu/M1FQVjo4Gx+hitbbdhoSkA5Azd7emGwc9EhhgwRH0I7/LJDEw1G+Z5d4tIMZysWdkAyCAGmH/qN+X5pSGQAe1/TBjYMLOS3l1zOzFJSvd20oBFhFWe/FBPOF6c4qg=" ],
+ "priority" : [ "100" ]
+ }
+ } ]
+ },
+ "internationalizationEnabled" : false,
+ "supportedLocales" : [ ],
+ "authenticationFlows" : [ {
+ "id" : "d94404c2-f668-4fe2-af3f-3444736b2a2f",
+ "alias" : "Account verification options",
+ "description" : "Method with which to verity the existing account",
+ "providerId" : "basic-flow",
+ "topLevel" : false,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "idp-email-verification",
+ "requirement" : "ALTERNATIVE",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "requirement" : "ALTERNATIVE",
+ "priority" : 20,
+ "flowAlias" : "Verify Existing Account by Re-authentication",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "f5b88790-3bd2-4a5c-b452-45ac724b2464",
+ "alias" : "Authentication Options",
+ "description" : "Authentication options.",
+ "providerId" : "basic-flow",
+ "topLevel" : false,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "basic-auth",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "basic-auth-otp",
+ "requirement" : "DISABLED",
+ "priority" : 20,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "auth-spnego",
+ "requirement" : "DISABLED",
+ "priority" : 30,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ } ]
+ }, {
+ "id" : "e47175a0-8291-4c10-95c1-863c2f1de51c",
+ "alias" : "Browser - Conditional OTP",
+ "description" : "Flow to determine if the OTP is required for the authentication",
+ "providerId" : "basic-flow",
+ "topLevel" : false,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "conditional-user-configured",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "auth-otp-form",
+ "requirement" : "REQUIRED",
+ "priority" : 20,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ } ]
+ }, {
+ "id" : "376389b4-0a1e-4188-ac0e-073969d19559",
+ "alias" : "Direct Grant - Conditional OTP",
+ "description" : "Flow to determine if the OTP is required for the authentication",
+ "providerId" : "basic-flow",
+ "topLevel" : false,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "conditional-user-configured",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "direct-grant-validate-otp",
+ "requirement" : "REQUIRED",
+ "priority" : 20,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ } ]
+ }, {
+ "id" : "e0961aff-bc85-4fcd-9887-954cd811fba4",
+ "alias" : "First broker login - Conditional OTP",
+ "description" : "Flow to determine if the OTP is required for the authentication",
+ "providerId" : "basic-flow",
+ "topLevel" : false,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "conditional-user-configured",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "auth-otp-form",
+ "requirement" : "REQUIRED",
+ "priority" : 20,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ } ]
+ }, {
+ "id" : "ff1b08fe-9b2b-4394-9c16-6e56f7248bb7",
+ "alias" : "Handle Existing Account",
+ "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider",
+ "providerId" : "basic-flow",
+ "topLevel" : false,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "idp-confirm-link",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "requirement" : "REQUIRED",
+ "priority" : 20,
+ "flowAlias" : "Account verification options",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "d5454fe8-06b8-45a2-841a-7c634f0eba15",
+ "alias" : "Reset - Conditional OTP",
+ "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.",
+ "providerId" : "basic-flow",
+ "topLevel" : false,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "conditional-user-configured",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "reset-otp",
+ "requirement" : "REQUIRED",
+ "priority" : 20,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ } ]
+ }, {
+ "id" : "a814256b-6307-4d0c-b7b6-9fe03d7afdab",
+ "alias" : "User creation or linking",
+ "description" : "Flow for the existing/non-existing user alternatives",
+ "providerId" : "basic-flow",
+ "topLevel" : false,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticatorConfig" : "create unique user config",
+ "authenticator" : "idp-create-user-if-unique",
+ "requirement" : "ALTERNATIVE",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "requirement" : "ALTERNATIVE",
+ "priority" : 20,
+ "flowAlias" : "Handle Existing Account",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "9a27a729-3207-4d42-9d54-aba248f88862",
+ "alias" : "Verify Existing Account by Re-authentication",
+ "description" : "Reauthentication of existing account",
+ "providerId" : "basic-flow",
+ "topLevel" : false,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "idp-username-password-form",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "requirement" : "CONDITIONAL",
+ "priority" : 20,
+ "flowAlias" : "First broker login - Conditional OTP",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "52c16b5a-faf6-4a4c-ba18-d6f70c29863d",
+ "alias" : "browser",
+ "description" : "browser based authentication",
+ "providerId" : "basic-flow",
+ "topLevel" : true,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "auth-cookie",
+ "requirement" : "ALTERNATIVE",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "auth-spnego",
+ "requirement" : "DISABLED",
+ "priority" : 20,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "identity-provider-redirector",
+ "requirement" : "ALTERNATIVE",
+ "priority" : 25,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "requirement" : "ALTERNATIVE",
+ "priority" : 30,
+ "flowAlias" : "forms",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "27df9fe7-78fe-44be-ae21-de72763b453d",
+ "alias" : "clients",
+ "description" : "Base authentication for clients",
+ "providerId" : "client-flow",
+ "topLevel" : true,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "client-secret",
+ "requirement" : "ALTERNATIVE",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "client-jwt",
+ "requirement" : "ALTERNATIVE",
+ "priority" : 20,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "client-secret-jwt",
+ "requirement" : "ALTERNATIVE",
+ "priority" : 30,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "client-x509",
+ "requirement" : "ALTERNATIVE",
+ "priority" : 40,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ } ]
+ }, {
+ "id" : "32cf0a27-795f-4285-8c12-6050d4836333",
+ "alias" : "direct grant",
+ "description" : "OpenID Connect Resource Owner Grant",
+ "providerId" : "basic-flow",
+ "topLevel" : true,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "direct-grant-validate-username",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "direct-grant-validate-password",
+ "requirement" : "REQUIRED",
+ "priority" : 20,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "requirement" : "CONDITIONAL",
+ "priority" : 30,
+ "flowAlias" : "Direct Grant - Conditional OTP",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "5975659c-8010-467e-b782-f0fcf1abb121",
+ "alias" : "docker auth",
+ "description" : "Used by Docker clients to authenticate against the IDP",
+ "providerId" : "basic-flow",
+ "topLevel" : true,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "docker-http-basic-authenticator",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ } ]
+ }, {
+ "id" : "98adec5d-98c6-4d7c-b6d3-105805e1e91e",
+ "alias" : "first broker login",
+ "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
+ "providerId" : "basic-flow",
+ "topLevel" : true,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticatorConfig" : "review profile config",
+ "authenticator" : "idp-review-profile",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "requirement" : "REQUIRED",
+ "priority" : 20,
+ "flowAlias" : "User creation or linking",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "88fa16c9-68da-49cd-82b9-30fd2714af6d",
+ "alias" : "forms",
+ "description" : "Username, password, otp and other auth forms.",
+ "providerId" : "basic-flow",
+ "topLevel" : false,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "auth-username-password-form",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "requirement" : "CONDITIONAL",
+ "priority" : 20,
+ "flowAlias" : "Browser - Conditional OTP",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "8c3fe87b-6b27-4bd1-b2b4-a63154550df2",
+ "alias" : "http challenge",
+ "description" : "An authentication flow based on challenge-response HTTP Authentication Schemes",
+ "providerId" : "basic-flow",
+ "topLevel" : true,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "no-cookie-redirect",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "requirement" : "REQUIRED",
+ "priority" : 20,
+ "flowAlias" : "Authentication Options",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "80910f52-988a-4c1a-b780-40399eafa7b0",
+ "alias" : "registration",
+ "description" : "registration flow",
+ "providerId" : "basic-flow",
+ "topLevel" : true,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "registration-page-form",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "flowAlias" : "registration form",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "feba6cf8-7689-4887-b73d-cae37150f548",
+ "alias" : "registration form",
+ "description" : "registration form",
+ "providerId" : "form-flow",
+ "topLevel" : false,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "registration-user-creation",
+ "requirement" : "REQUIRED",
+ "priority" : 20,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "registration-profile-action",
+ "requirement" : "REQUIRED",
+ "priority" : 40,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "registration-password-action",
+ "requirement" : "REQUIRED",
+ "priority" : 50,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "registration-recaptcha-action",
+ "requirement" : "DISABLED",
+ "priority" : 60,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ } ]
+ }, {
+ "id" : "b2950822-d435-463d-860b-920144bc5543",
+ "alias" : "reset credentials",
+ "description" : "Reset credentials for a user if they forgot their password or something",
+ "providerId" : "basic-flow",
+ "topLevel" : true,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "reset-credentials-choose-user",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "reset-credential-email",
+ "requirement" : "REQUIRED",
+ "priority" : 20,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "authenticator" : "reset-password",
+ "requirement" : "REQUIRED",
+ "priority" : 30,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ }, {
+ "requirement" : "CONDITIONAL",
+ "priority" : 40,
+ "flowAlias" : "Reset - Conditional OTP",
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : true
+ } ]
+ }, {
+ "id" : "4070ca61-2129-4835-a890-45388c060a9b",
+ "alias" : "saml ecp",
+ "description" : "SAML ECP Profile Authentication Flow",
+ "providerId" : "basic-flow",
+ "topLevel" : true,
+ "builtIn" : true,
+ "authenticationExecutions" : [ {
+ "authenticator" : "http-basic-authenticator",
+ "requirement" : "REQUIRED",
+ "priority" : 10,
+ "userSetupAllowed" : false,
+ "autheticatorFlow" : false
+ } ]
+ } ],
+ "authenticatorConfig" : [ {
+ "id" : "b616d8ec-25ee-4b8e-9924-b7ff19a89e0f",
+ "alias" : "create unique user config",
+ "config" : {
+ "require.password.update.after.registration" : "false"
+ }
+ }, {
+ "id" : "302dcbad-33e1-45d7-a4fd-4f4afccbe8eb",
+ "alias" : "review profile config",
+ "config" : {
+ "update.profile.on.first.login" : "missing"
+ }
+ } ],
+ "requiredActions" : [ {
+ "alias" : "CONFIGURE_TOTP",
+ "name" : "Configure OTP",
+ "providerId" : "CONFIGURE_TOTP",
+ "enabled" : true,
+ "defaultAction" : false,
+ "priority" : 10,
+ "config" : { }
+ }, {
+ "alias" : "terms_and_conditions",
+ "name" : "Terms and Conditions",
+ "providerId" : "terms_and_conditions",
+ "enabled" : false,
+ "defaultAction" : false,
+ "priority" : 20,
+ "config" : { }
+ }, {
+ "alias" : "UPDATE_PASSWORD",
+ "name" : "Update Password",
+ "providerId" : "UPDATE_PASSWORD",
+ "enabled" : true,
+ "defaultAction" : false,
+ "priority" : 30,
+ "config" : { }
+ }, {
+ "alias" : "UPDATE_PROFILE",
+ "name" : "Update Profile",
+ "providerId" : "UPDATE_PROFILE",
+ "enabled" : true,
+ "defaultAction" : false,
+ "priority" : 40,
+ "config" : { }
+ }, {
+ "alias" : "VERIFY_EMAIL",
+ "name" : "Verify Email",
+ "providerId" : "VERIFY_EMAIL",
+ "enabled" : true,
+ "defaultAction" : false,
+ "priority" : 50,
+ "config" : { }
+ }, {
+ "alias" : "update_user_locale",
+ "name" : "Update User Locale",
+ "providerId" : "update_user_locale",
+ "enabled" : true,
+ "defaultAction" : false,
+ "priority" : 1000,
+ "config" : { }
+ } ],
+ "browserFlow" : "browser",
+ "registrationFlow" : "registration",
+ "directGrantFlow" : "direct grant",
+ "resetCredentialsFlow" : "reset credentials",
+ "clientAuthenticationFlow" : "clients",
+ "dockerAuthenticationFlow" : "docker auth",
+ "attributes" : {
+ "clientOfflineSessionMaxLifespan" : "0",
+ "clientSessionIdleTimeout" : "0",
+ "clientSessionMaxLifespan" : "0",
+ "clientOfflineSessionIdleTimeout" : "0"
+ },
+ "keycloakVersion" : "11.0.1",
+ "userManagedAccessAllowed" : false
+}
\ No newline at end of file
diff --git a/deploy/cleanup_json.py b/deploy/cleanup_json.py
new file mode 100644
index 0000000..d96a544
--- /dev/null
+++ b/deploy/cleanup_json.py
@@ -0,0 +1,17 @@
+
+import os
+import sys
+import json
+
+def clean(path):
+ os.system("json-dereference -s {} -o {}".format(path, path))
+
+def main():
+ for root, dirs, files in os.walk(sys.argv[1], topdown=False):
+ for name in files:
+ if name.endswith("json") and not name.endswith("endpoints.json"):
+ print(os.path.join(root, name))
+ clean(os.path.join(root, name))
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/deploy/conf.py b/deploy/conf.py
new file mode 100644
index 0000000..4d97e0e
--- /dev/null
+++ b/deploy/conf.py
@@ -0,0 +1,125 @@
+"""Beacon Configuration."""
+
+#
+# Beacon general info
+#
+beacon_id = 'org.ega-archive.ga4gh-approval-beacon-test' # ID of the Beacon
+beacon_name = 'GA4GH Approval Beacon Test' # Name of the Beacon service
+api_version = 'v2.0.0' # Version of the Beacon implementation
+uri = 'https://beacon-giab-test.ega-archive.org'
+beacon_granularity = "record"
+max_beacon_granularity = "record"
+
+#
+# Organization info
+#
+org_id = 'EGA' # Id of the organization
+org_name = 'European Genome-Phenome Archive (EGA)' # Full name
+org_description = ('The European Genome-phenome Archive (EGA) '
+ 'is a service for permanent archiving and sharing '
+ 'of all types of personally identifiable genetic '
+ 'and phenotypic data resulting from biomedical research projects.')
+org_adress = ('C/ Dr. Aiguader, 88'
+ 'PRBB Building'
+ '08003 Barcelona, Spain')
+org_welcome_url = 'https://ega-archive.org/'
+org_contact_url = 'mailto:beacon.ega@crg.eu'
+org_logo_url = 'https://ega-archive.org/images/logo.png'
+org_info = ''
+
+#
+# Project info
+#
+description = (r"This Beacon "
+ r"is based on the GA4GH Beacon "
+ r"v2.0")
+version = 'v2.0'
+welcome_url = 'https://beacon.ega-archive.org/'
+alternative_url = 'https://beacon.ega-archive.org/api'
+create_datetime = '2021-11-29T12:00:00.000000'
+update_datetime = ''
+# update_datetime will be created when initializing the beacon, using the ISO 8601 format
+
+#
+# Service
+#
+service_type = 'org.ga4gh:beacon:1.0.0' # service type
+service_url = 'https://beacon.ega-archive.org/api/services'
+entry_point = False
+is_open = True
+documentation_url = 'https://github.com/EGA-archive/beacon-2.x/' # Documentation of the service
+environment = 'test' # Environment (production, development or testing/staging deployments)
+
+# GA4GH
+ga4gh_service_type_group = 'org.ga4gh'
+ga4gh_service_type_artifact = 'beacon'
+ga4gh_service_type_version = '1.0'
+
+# Beacon handovers
+beacon_handovers = [
+ {
+ 'handoverType': {
+ 'id': 'CUSTOM',
+ 'label': 'Project description'
+ },
+ 'note': 'Project description',
+ 'url': 'https://www.nist.gov/programs-projects/genome-bottle'
+ }
+]
+
+#
+# Database connection
+#
+database_host = '127.0.0.1'
+database_port = 27017
+database_user = 'vpbib'
+database_password = 'vpbib'
+database_name = 'beacon'
+database_auth_source = 'admin'
+# database_schema = 'public' # comma-separated list of schemas
+# database_app_name = 'beacon-appname' # Useful to track connections
+
+#
+# Web server configuration
+# Note: a Unix Socket path is used when behind a server, not host:port
+#
+beacon_host = '0.0.0.0'
+beacon_port = 5050
+beacon_tls_enabled = False
+beacon_tls_client = False
+beacon_cert = '/etc/ega/server.cert'
+beacon_key = '/etc/ega/server.key'
+CA_cert = '/etc/ega/CA.cert'
+
+#
+# Permissions server configuration
+#
+permissions_url = 'http://beacon-permissions'
+
+#
+# IdP endpoints (OpenID Connect/Oauth2)
+#
+# or use Elixir AAI (see https://elixir-europe.org/services/compute/aai)
+#
+idp_client_id = 'beacon'
+idp_client_secret = 'b26ca0f9-1137-4bee-b453-ee51eefbe7ba' # same as in the test IdP
+idp_scope = 'profile openid'
+
+idp_authorize = 'http://idp/auth/realms/Beacon/protocol/openid-connect/auth'
+idp_access_token = 'http://idp/auth/realms/Beacon/protocol/openid-connect/token'
+idp_introspection = 'http://idp/auth/realms/Beacon/protocol/openid-connect/token/introspect'
+idp_user_info = 'http://idp/auth/realms/Beacon/protocol/openid-connect/userinfo'
+idp_logout = 'http://idp/auth/realms/Beacon/protocol/openid-connect/logout'
+
+idp_redirect_uri = 'http://beacon:5050/login'
+
+#
+# UI
+#
+autocomplete_limit = 16
+autocomplete_ellipsis = '...'
+
+#
+# Ontologies
+#
+ontologies_folder = "ontologies"
\ No newline at end of file
diff --git a/deploy/data/datasets.json b/deploy/data/datasets.json
new file mode 100644
index 0000000..53c03f4
--- /dev/null
+++ b/deploy/data/datasets.json
@@ -0,0 +1,2523 @@
+ [
+ {
+ "createDateTime": "2017-04-30T00:00:00+00:00",
+ "description": "The Genome in a Bottle Consortium, hosted by the National Institute of Standards and Technology (NIST) is creating reference materials and data for human genome sequencing, as well as methods for genome comparison and benchmarking. ",
+ "externalUrl": "https://www.nature.com/articles/sdata201625, https://jimb.stanford.edu/giab-resources",
+ "id": "EGAD00001008097",
+ "name": "The Genome in a Bottle Consortium (GIAB)",
+ "updateDateTime": "2017-04-30T00:00:00+00:00"
+ }
+ ,
+ {
+ "id": "7DC8EF10-67Ac-C0aE-Cc7D-c3CEFa6BDd8A",
+ "name": "The Plant Your Health study",
+ "description": "The effects of an 8-week vegan diet on Trimethylamine-N-Oxide (TMAO) levels and post-challenge glucose levels in individuals with dysglycaemia..; Purpose: To investigate the effect of an 8-week vegan diet on TMAO plasma levels and 3-hour post-challenge gl",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "The Plant Your Health study"
+ },
+ {
+ "id": "0b8FfBE9-4b7B-b4D9-ec3D-c2C3eAF6a4f5",
+ "name": "STAND UP - Experimental intervention",
+ "description": "STAND UP Sedentary behaviour in older adults: investigating a new therapeutic paradigm Work Package 3: Investigating the effect of sedentary time, reduced sedentary time and increased light-intensity physical activity on metabolic and psychological health",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "STAND UP - Experimental intervention"
+ },
+ {
+ "id": "937FBbda-0fAC-BabE-Fcd1-E84A3bf51c6C",
+ "name": "STAND UP - Cut-point validation study",
+ "description": "STAND UP - Sedentary behaviour in older adults: investigating a new therapeutic paradigm Work Package 1: Classification validation for assessment of objective sedentary behaviour and physical activity in older adults",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "STAND UP - Cut-point validation study"
+ },
+ {
+ "id": "2f3abC4A-C7D6-7ac5-4D73-5DFf20d4aeC6",
+ "name": "SMArT Work: Stand More at Work",
+ "description": "SMArT Work: Stand More AT Work The development of behaviour change strategies for increasing standing and movement among NHS office based staff working in Leicestershire Hospitals",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "SMArT Work: Stand More at Work"
+ },
+ {
+ "id": "87Eb15F2-25D8-BCca-1236-bDda6097c142",
+ "name": "Type 1 Activity and Glucose (TAG1) study",
+ "description": "Type 1 Activity and Glucose (TAG1) study; A pilot study informing the feasibility and design of a continuous measures physical activity intervention in young adults with type 1 diabetes mellitus. Type 1 Activity and Glucose Study TAG1",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "Type 1 Activity and Glucose (TAG1) study"
+ },
+ {
+ "id": "B0Ac7d98-3B9A-1597-35a7-aAF8C7E2cB6e",
+ "name": "The REACT study",
+ "description": "The REACT study: Establishing what relationship exists between fungal colonisation and allergy and the clinical, radiological and pathological characteristics of lung disease",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "The REACT study"
+ },
+ {
+ "id": "EFaD523A-F97A-bA2B-D72B-c820eBF4E5a1",
+ "name": "The Leicester Institute for Lung Health Research Tissue Bank",
+ "description": "The Leicester Institute for Lung Health Research Tissue Bank",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "The Leicester Institute for Lung Health Research Tissue Bank"
+ },
+ {
+ "id": "58BA70aF-A4D6-5460-41CA-1fFA56CDdEb8",
+ "name": "Study of Mepolizumab in Patients with HES Who Receive Standard Therapy",
+ "description": "A randomized, double-blind, placebo-controlled study to investigate the efficacy and safety of mepolizumab in the treatment of adolescent and adult subjects with severe hypereosinophilic syndrome",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "Study of Mepolizumab in Patients with HES Who Receive Standard Therapy"
+ },
+ {
+ "id": "F7Ccf1ae-a7C3-A0Be-170d-b0476ae2EBC9",
+ "name": "Study of mepolizumab in patients with HES from Study 200622",
+ "description": "A multi-centre, open-label extension, safety study to describe the longterm clinical experience of mepolizumab in participants with hypereosinophilic syndrome (HES) from Study 200622",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "Study of mepolizumab in patients with HES from Study 200622"
+ },
+ {
+ "id": "a3ceE2B0-dF6B-5E9f-2eED-c75dC1BAFeD0",
+ "name": "RESP 4683",
+ "description": "Mepolizumab Long-term Access Programme for Subjects who Participated in Study MEA115921 (Placebo-controlled Study of Mepolizumab in the Treatment of Eosinophilic Granulomatosis with Polyangiitis in Subjects Receiving Standard-of-care Therapy) RESP - 4683",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "RESP 4683"
+ },
+ {
+ "id": "CBd3e248-baAF-BFAc-a5bB-dA6a35980e47",
+ "name": "Phenotyping bronchiectasis over 2 years including a macrolide trial",
+ "description": "Phenotyping bronchiectasis over 2 years including a macrolide trial; Phenotyping bronchiectasis based on aetiology, exacerbation characteristics and response to erythromycin.",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "Phenotyping bronchiectasis over 2 years including a macrolide trial"
+ },
+ {
+ "id": "9c7f5bD8-e48f-1962-c51B-d6085e9bEcA7",
+ "name": "MLTC",
+ "description": " Use of tissue from lung resections to investigate the molecular and functional mechanisms of human lung disease",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "MLTC"
+ },
+ {
+ "id": "FB15eDb9-fcd8-B7DA-5Bb1-e2aB7C61bFAE",
+ "name": "GSK3772847 in participants with Asthma with AFAD",
+ "description": "A double blind (sponsor open) placebo-controlled, stratified, parallel group study to evaluate the efficacy and safety of repeat doses of GSK3772847 in participants with moderate to severe asthma with allergic fungal airway disease (AFAD)",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "GSK3772847 in participants with Asthma with AFAD"
+ },
+ {
+ "id": "8b4D2Fdc-34ae-16D0-c650-D879d2Ba4c6e",
+ "name": "DETECTION OF METHACHOLINE CHALLENGE INDUCED ASTHMA SYMPTOMS USING A NOVEL DEVICE.",
+ "description": "DETECTION OF METHACHOLINE CHALLENGE INDUCED ASTHMA SYMPTOMS USING A NOVEL DEVICE",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "DETECTION OF METHACHOLINE CHALLENGE INDUCED ASTHMA SYMPTOMS USING A NOVEL DEVICE."
+ },
+ {
+ "id": "cBCE5740-78ec-aC52-e8bC-c71dfFCB4e26",
+ "name": "Heart Outcomes Prevention Evaluation (HOPE)- 3 (version 1.6.1)",
+ "description": " Heart Outcomes Prevention Evaluation (HOPE)- 3. A large simple randomized trial of combined cholesterol modification and blood pressure lowering in middle aged people at average risk",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "Heart Outcomes Prevention Evaluation (HOPE)- 3 (version 1.6.1)"
+ },
+ {
+ "id": "027BDaEC-03f7-b97c-fbd8-F9Dbe47816d3",
+ "name": "Extended cohort for e-health, environment and DNA (EXCEED) Study",
+ "description": "Extended cohort for e-health, environment and DNA (EXCEED) Study",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "Extended cohort for e-health, environment and DNA (EXCEED) Study"
+ },
+ {
+ "id": "6b0D2daC-3bEa-E8C7-26cE-a3E71cbeD24f",
+ "name": "CHALLENGE-UK: A UK cohort of the CHALLENGE trial",
+ "description": " CHALLENGE-UK: A UK cohort of a Phase III study (CHALLENGE: the Colon Health and Lifelong Exercise Change study) of the impact of a physical activity programme on disease-free survival in patients with high risk Stage II or Stage III colon cancer: A Ran",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "CHALLENGE-UK: A UK cohort of the CHALLENGE trial"
+ },
+ {
+ "id": "91Ffd52B-F0aD-Fb8B-c25E-eC9FD1c3dab4",
+ "name": "CELEB: lung volume reduction in COPD - surgery vs endobronchial valves",
+ "description": "The CELEB trial: Comparative Effectiveness of Lung volume reduction surgery for Emphysema and Bronchoscopic lung volume reduction with valve placement; People with emphysema have lungs that become baggy and full of holes meaning that they are unable to br",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "CELEB: lung volume reduction in COPD - surgery vs endobronchial valves"
+ },
+ {
+ "id": "C67bEdDe-f1b2-f6E4-52C0-DC98EA50f2c4",
+ "name": "Yorkshire heart failure and assessment risk trial (Yorkshire HEART)",
+ "description": "Prospective validation of prognostic markers in patients with chronic heart failure",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "Yorkshire heart failure and assessment risk trial (Yorkshire HEART)"
+ },
+ {
+ "id": "3489eFfb-E58e-af7D-E7d9-42fbA9e0371C",
+ "name": "TRANSITION_LCZ696 pre/ post discharge in acute heart failure",
+ "description": "A multicenter, randomized, open label, parallel group study comparing pre-discharge and posT-discharge tReatment initiation with LCZ696 in heArt failure patieNtS with reduced ejectIon-fracTion hospItalized for an acute decOmpensation eveNt (ADHF) (the TRA",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "TRANSITION_LCZ696 pre/ post discharge in acute heart failure"
+ },
+ {
+ "id": "37C6d8BE-3D1C-0AaF-DCa3-C3286E1BFAD4",
+ "name": "Phase 2 with Elamipretide in Subjects with Congestive Heart Failure",
+ "description": "A Phase 2 Randomized, Double-Blind, Placebo-Controlled Study to Evaluate the Cardiac and Renal Effects of Short Term Treatment with Elamipretide in Patients Hospitalized with Congestion due to Heart Failure; Heart failure is a major cause of large economi",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "Phase 2 with Elamipretide in Subjects with Congestive Heart Failure"
+ },
+ {
+ "id": "E2CD0A84-dbE6-d3f1-e85B-8D1A7dBc543C",
+ "name": "PARADISE-MI",
+ "description": "A multi-center, randomized, double-blind, active-controlled, parallelgroup Phase 3 study to evaluate the efficacy and safety of LCZ696 compared to ramipril on morbidity and mortality in patients with left ventricular dysfunction following an acute myoc",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "PARADISE-MI"
+ },
+ {
+ "id": "9ef1a4DC-Be7F-c5DA-AFE7-F1cA53DCad76",
+ "name": "LENTEN",
+ "description": "Investigation of molecular forms of ANP and BNP in patients with heart failure treated with ACE inhibitor and following switch to sacubitril valsartan.; Purpose: To investigate differences in processing in the circulation of BNP and ANP in the setting of ",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "LENTEN"
+ },
+ {
+ "id": "d4eE0F6A-CBE7-b0Ac-08D7-597eD64cC0d2",
+ "name": "IRONMAN",
+ "description": "Effectiveness of intravenous iron treatment vs standard care in patients with heart failure and iron deficiency: a randomised, open-label multicentre trial (IRONMAN); Purpose: To establish in patients with chronic heart failure and iron deficiency whether",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "IRONMAN"
+ },
+ {
+ "id": "f167e20A-8630-5A92-B0A2-bD8fC4d7aB2c",
+ "name": "HOT (previously NEON)",
+ "description": "Does Home Oxygen Therapy (HOT) in Addition to Standard Care Reduce Disease Severity and Improve Symptoms in Patients with Chronic Heart Failure?; What is the role of home oxygen therapy in the management of patients with CHF? This study aims to address t",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "HOT (previously NEON)"
+ },
+ {
+ "id": "b1a3ADe5-d8Eb-43Ba-AF8C-46dFcD3A215a",
+ "name": "EMPEROR-Reduced Study (1245.121)",
+ "description": "A phase III randomised, double-blind trial to evaluate efficacy and safety of once daily empagliflozin 10 mg compared to placebo, in patients with chronic Heart Failure with reduced Ejection Fraction(HFrEF). This randomised, double-blind, multi-national,",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "EMPEROR-Reduced Study (1245.121)"
+ },
+ {
+ "id": "F1D562c8-15Ce-1D2f-bBCa-b7EBA53FCdc6",
+ "name": "EMPEROR-Preserved Study (1245.110)",
+ "description": "A phase III randomised, double-blind trial to evaluate efficacy and safety of once daily empagliflozin 10 mg compared to placebo, in patients with chronic Heart Failure with preserved Ejection Fraction (HFpEF).; Purpose: A phase III randomised, double-bli",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "EMPEROR-Preserved Study (1245.110)"
+ },
+ {
+ "id": "FeB61bcE-fDe4-6AD2-b82C-7BEbF0328e64",
+ "name": "CCRN 2238 (Heart failure) - RELAX 2 - Serelaxin when added to standard therapy in acute heart failure",
+ "description": "RELAX 2 - Serelaxin when added to standard therapy in acute heart failure; A multicenter, randomized, double-blind, placebo-controlled phase III study to evaluate the efficacy, safety and tolerability of Serelaxin when added to standard therapy in acute h",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "CCRN 2238 (Heart failure) - RELAX 2 - Serelaxin when added to standard therapy in acute heart failure"
+ },
+ {
+ "id": "B0dFab9E-B6Ab-FC91-2CB6-6F7ea52d84Ac",
+ "name": "CCRN 127 (CHF)",
+ "description": "A Multi-Center, Randomized, Double-Blind, Parallel Group, Active-Controlled Study To Evaluate The Efficacy And Safety Of LCZ696 Therapy Compared To Enalapril On Morbidity And Mortality In Patients With Chronic Heart Failure (NYHA Class II - IV) With Reduc",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "CCRN 127 (CHF)"
+ },
+ {
+ "id": "dfbc926e-4ABb-Ae1C-a1cE-d509a832Efb6",
+ "name": "CARD 5650",
+ "description": "A randomized parallel-group, placebo-controlled, double-blind, event-driven, multi-center pivotal phase III clinical outcome trial of efficacy and safety of the oral sGC stimulator Vericiguat in subjects with heart failure and reduced ejection fraction (H",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "CARD 5650"
+ },
+ {
+ "id": "7aA58D3f-cAC5-9EB6-9Cab-f2b8BcCA1Eea",
+ "name": "SPARK Part 1",
+ "description": "]Selfmanagement programme for improving health through Physical Activity in chRonic Kidney disease.",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "SPARK Part 1"
+ },
+ {
+ "id": "54AbB3f0-cE5a-86BA-FA3d-e07bfAd52934",
+ "name": "QCKD",
+ "description": "Increasing Physical Activity in Chronic Kidney Disease : The Patient Perspective (QCKD); Increasing Physical Activity in Chronic Kidney Disease : The Patient Perspective (QCKD)",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "QCKD"
+ },
+ {
+ "id": "B4fDCe85-B53b-5429-AecE-6F1DEeC09834",
+ "name": "PINK",
+ "description": "Physical Activity, Immune Function and INflammation in Kidney Patients ; ",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "PINK"
+ },
+ {
+ "id": "45f83Ba9-EbF4-B2F0-a1Fe-5aAB80241dc6",
+ "name": "PEArL",
+ "description": "Programmes for Exercise and an Active Lifestyle in Kidney Disease",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "PEArL"
+ },
+ {
+ "id": "b93C0cd5-0Dc3-13F4-b974-a8ed06F4f37D",
+ "name": "PACE-KD",
+ "description": "Participant Acceptability of Exercise in Kidney Disease. There are ~30,000 UK renal transplant recipients (RTRs), with patient care costs less than half than for dialysis. However, cardiovascular disease (CVD) is a major cause of morbidity and mortalit",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "PACE-KD"
+ },
+ {
+ "id": "943eC8cF-5Fa7-92B0-7c2e-46dE2Dac7FbB",
+ "name": "Motivation After Exercise in Chronic Kidney Disease: MAX CKD",
+ "description": "Motivation After Exercise in Chronic Kidney Disease: MAX CKD",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "Motivation After Exercise in Chronic Kidney Disease: MAX CKD"
+ },
+ {
+ "id": "ade1F6D7-1a9F-B130-0dA9-C4Df2958F1B7",
+ "name": "I-RACE",
+ "description": "Intramuscular and Inflammatory Response to Acute Exercise in Chronic Disease (I-RACE); Chronic kidney disease patients often suffer from muscle wasting and weakness which adversely impacts quality of life, physical activity, physical functioning and morta",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "I-RACE"
+ },
+ {
+ "id": "8e650f19-5DB3-BA58-6D7F-4f1Db35C967c",
+ "name": "Exercise Training in Chronic Kidney Disease",
+ "description": "ExTra CKD; Can the addition of resistance exercise to a cardiovascular exercise programme provide muscle benefits in addition to cardiovascular benefits? Can this combined exercise programme also improve -exercise capacity -physical functioning -quali",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "Exercise Training in Chronic Kidney Disease"
+ },
+ {
+ "id": "241DBc6e-DbB2-43da-f809-eFc1D8940ACa",
+ "name": "EXPLORE CKD",
+ "description": "Exploring the mechanisms of muscle wasting in CKD; Patients with Chronic Kidney Disease (CKD) suffer with muscle wasting which is an important clinical problem as it is strongly associated with morbidity and mortality and can begin very early in the disea",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "EXPLORE CKD"
+ },
+ {
+ "id": "F4c0Baf2-Ba73-450d-aA0b-AED43ea6fBC9",
+ "name": "COCO Tx",
+ "description": "COCO Tx; Cardiovascular Risk Factors and Physical Condition in Kidney Transplant Recipients",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "COCO Tx"
+ },
+ {
+ "id": "5Dbf1B0E-3FaB-b805-3aef-Ace58D4C036F",
+ "name": "WP4 Exercise Outcome Study",
+ "description": "; Purpose: A Comprehensive Comparison of the Sensitivity of Common Exercise Outcome Measures for Chronic Obstructive Pulmonary Disease (COPD)",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "WP4 Exercise Outcome Study"
+ },
+ {
+ "id": "abdCF9B7-d0f4-153C-aD7B-4E50aDdC7bec",
+ "name": "PCRN06/CCRN058 (CAD - SIGNIFY)",
+ "description": "Study assessing the morbi-mortality benefits of the If inhibitor Ivabradine in patients with coronary artery disease (SIGNIFY)",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "PCRN06/CCRN058 (CAD - SIGNIFY)"
+ },
+ {
+ "id": "b52DaB0A-6C1f-f5F2-b8Df-E3e9CA5cB6F1",
+ "name": "GRAPHIC",
+ "description": "Genetic regulation of arterial pressure in humans in the community: The Graphic Study GRAPHIC",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "GRAPHIC"
+ },
+ {
+ "id": "AF19CaEe-2DFd-F4c8-8fcB-EAfCe5ca96dB",
+ "name": "GENVASC",
+ "description": "The GENVASC Study: Genetics and the Vascular Health Check Programme",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "GENVASC"
+ },
+ {
+ "id": "Ec6eBf95-cA2B-A59B-14Ba-c1962aAdDB50",
+ "name": "BRICCS",
+ "description": "Sample and Data Collection for Cardiovascular Research",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "BRICCS"
+ },
+ {
+ "id": "1C7c4Ee3-ad8f-F71d-75fE-0C5A1deFBfaE",
+ "name": "CARD 4843",
+ "description": "A phase III, double-blind, randomized placebo-controlled study to evaluate the effects of dalcetrapib on cardiovascular (CV) risk in a genetically defined population with a recent Acute Coronary Syndrome (ACS): The Dal-GenE trial; Coronary heart disease ",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "CARD 4843"
+ },
+ {
+ "id": "7e1FbAcC-e3db-7ea4-f4cb-A65a39CEbD70",
+ "name": "ACtiF - RCT and parallel process evaluation (WP 3.2 and 3.3)",
+ "description": "Development and evaluation of an intervention to support Adherence to treatment in adults with Cystic Fibrosis. A randomised controlled trial and parallel process evaluation.; Cystic Fibrosis (CF) affects 10000 people in the UK. The lungs of people with C",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "ACtiF - RCT and parallel process evaluation (WP 3.2 and 3.3)"
+ },
+ {
+ "id": "95c4eabC-F589-d1E6-Bb2E-1c8DE7dbABaF",
+ "name": "Standard Care versus Triventricular Pacing in Heart Failure (STRIVE HF)",
+ "description": "A multicentre randomised control trial comparing standard cardiac resynchronisation pacing with triventricular pacing; Many patients with heart failure have problems with the electrical impulses that cause the heart to contract resulting in unsynchronised",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "Standard Care versus Triventricular Pacing in Heart Failure (STRIVE HF)"
+ },
+ {
+ "id": "B9f870aD-d25f-fE3e-AC2E-21EcD478dA9F",
+ "name": "Sample and data collection for diastolic heart failure study",
+ "description": "Sample and data collection for diastolic heart failure study; Sample and data collection for diastolic heart failure study: Biomarkers for Diastolic Heart Failure",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "Sample and data collection for diastolic heart failure study"
+ },
+ {
+ "id": "f7eD02bF-5b8d-Caf5-5f7F-e5F9EC24c7AD",
+ "name": "INDAPAMIDE",
+ "description": "Treatment of heart failure using indapamide : a pilot study of its effect on plasma FGF23; Other clinical trial to study a novel intervention or randomised clinical trial to compare interventions in clinical practice",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "INDAPAMIDE"
+ },
+ {
+ "id": "fBDbc3da-fac5-5B9C-1EBA-aC85B7A4D3f2",
+ "name": "UNTOUCHED",
+ "description": "Understanding Outcomes with the EMBLEM S-ICD in Primary Prevention Patients with Low Ejection Fraction; This study assesses the 18-month incidence of inappropriate shocks in subjects implanted with the EMBLEM Subcutaneous Implantable Defibrillator (S-ICD)",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "UNTOUCHED"
+ },
+ {
+ "id": "382C50a7-5b6D-56E4-bacd-F3eb956724Aa",
+ "name": "REM-HF",
+ "description": "Remote monitoring an evaluation of implantable devices for management of heart failure patients REM-HF; There is a pressing need to develop new ways of managing the rapidly increasing number of people living with heart failure in the UK. The epidemic of h",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "REM-HF"
+ },
+ {
+ "id": "2A4bCfeE-a8AF-02EA-c4AE-f6Aa0c7b514e",
+ "name": "NOAH - AFNET 6",
+ "description": "Non-vitamin K antagonist Oral anticoagulants in patients with Atrial High rate episodes; Patients with Atrial Fibrillation (irregular rhythm and frequency in the hearts atrium) (AF) are known to have an increased risk of stroke. In order to prevent stroke",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "NOAH - AFNET 6"
+ },
+ {
+ "id": "7C963F1E-9cBa-b4c7-d6C0-cDB01aEFf8b2",
+ "name": "MINERVA",
+ "description": "Multicentre Investigation of Novel Electrocardiogram Risk markers in Ventricular Arrhythmia prediction ; Basic study involving procedures with human participants",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "MINERVA"
+ },
+ {
+ "id": "afc9A2D0-de8f-Ca2f-c34A-8bA59e6E43F2",
+ "name": "MicraTM Transcatheter Pacing System (Micra) Registry",
+ "description": "Product Surveillance Registry A prospective, noninterventional registry providing continuing evaluation and periodic reporting of product safety, effectiveness and patient outcomes across Medtronic marketreleased products within diabetes, cardiac rhy",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "MicraTM Transcatheter Pacing System (Micra) Registry"
+ },
+ {
+ "id": "Ae34a1Cc-E214-0efB-BA87-1cC4Ffbd2a9A",
+ "name": "Linear LME-167 CARD 5494",
+ "description": "Evaluation of a Multi-Electrode Linear Type Catheter (D-1368-01-SI) for Endocardial Ablation of Patients with Persistent Atrial Fibrillation.; The purpose of this trial is to assess acute safety and performance of the Multi-electrode Linear Type Catheter ",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "Linear LME-167 CARD 5494"
+ },
+ {
+ "id": "fe3ECaF9-8BD5-baCD-1098-48CBD6731Ee2",
+ "name": "HOPE",
+ "description": "AV optimisation delivered with direct His bundle pacing, in patients with heart failure, long PR without left bundle branch block: randomised multiÂÂcentre clinical outcome study The His Optimised Pacing Evaluated for Heart Failure Trial (HOPEÂÂ-HF); Thi",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "HOPE"
+ },
+ {
+ "id": "b17f3D42-8A0b-c8b5-2367-05c417Fd36Cf",
+ "name": "EAST - Early Treatment of Atrial Fibrillation for Stroke Prevention Trial",
+ "description": "An Investigator-driven, Prospective, Parallel-group, Randomized, Open, Blinded Outcome Assessment (PROBE-design), Multi-centre Trial for the Prevention of Stroke in High-risk Subjects with Atrial Fibrillation.; Atrial fibrillation (AF) is the most common ",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "EAST - Early Treatment of Atrial Fibrillation for Stroke Prevention Trial"
+ },
+ {
+ "id": "CfFb0d9E-87c1-AC10-bAF2-ED50dac8b97F",
+ "name": "MesoTRAP feasibility study",
+ "description": "MesoTRAP: A feasibility study comparing video-assisted thoracoscopic partial pleurectomy/decortication with indwelling pleural catheter in patients with trapped lung due to malignant pleural mesothelioma designed to address recruitment and randomisation u",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "MesoTRAP feasibility study"
+ },
+ {
+ "id": "CBEFf057-C36A-BfCF-D985-D5FAd7f38e60",
+ "name": "The MaRACAS Study",
+ "description": "An observational case control study to identify the role of Microvesicles (MV) and MV derived microRNA (miRNA) in post cardiac surgery Acute Kidney Injury (AKI): The MaRACAS Study; An observational case control study to identify the role of Microvesicles",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "The MaRACAS Study"
+ },
+ {
+ "id": "9F61cEBe-e68c-c925-9Ca1-7A9d6cF521BD",
+ "name": "REVAKI--2",
+ "description": "A FEASIBILITY STUDY TO CONSIDER THE RELATIONSHIP BETWEEN MARKERS OF RED CELL DAMAGE, INFLAMMATION AND THE RECOVERY PROCESS OF NEWBORNS REQUIRING EXTRACORPOREAL MEMBRANE OXYGENATION (ECMO) FOR PERSISTENT PULMONARY HYPERTENSION OF THE NEWBORN (PPHN); Respir",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "REVAKI--2"
+ },
+ {
+ "id": "bA9c38E4-a8bc-e4aA-c5C6-89aDb3EfCB1A",
+ "name": "Obesity Paradox and Epigenetics in Cardiac Surgery",
+ "description": "An observational case control study to identify the role of epigenetic regulation of genes responsible for energy; This is a prospective, single-centre case control comparison of expression of target genes responsible for energy utilisation, mitochondria",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "Obesity Paradox and Epigenetics in Cardiac Surgery"
+ },
+ {
+ "id": "C0cBDbaf-dD2c-1BbE-605C-2B09D1E7Ca3e",
+ "name": "Pharmacist SIMPLE Asthma Intervention",
+ "description": "Pharmacist SIMPLE Asthma Intervention; : A study to evaluate the efficacy of a SIMPLE intervention to support medicine adherence for people with difficult to control asthma",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "Pharmacist SIMPLE Asthma Intervention"
+ },
+ {
+ "id": "7Aaf04D6-1a3F-6BF9-bFf7-EB928CA3F04b",
+ "name": "Pilot study investigating longer-term cardiac effects of pre-eclampsia",
+ "description": "Pilot study to confirm that a history of pre-eclampsia is associated with adverse indices of cardiac function.; We will test the hypothesis that a history of pre-eclampsia is associated with adverse indices of cardiac function.",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "Pilot study investigating longer-term cardiac effects of pre-eclampsia"
+ },
+ {
+ "id": "0Dc58f72-C15d-EC6A-89f1-2ca84be5Dd0E",
+ "name": "HCMR Study",
+ "description": "HCMR - Novel Predictors of Outcome in Hypertrophic Cardiomyopathy; This is a multi-centre, observational, prospective study of patients with clinically diagnosed hypertrophic cardiomyopathy, studied at baseline with collection of demographic data, clinica",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "HCMR Study"
+ },
+ {
+ "id": "7Ac40bFa-1bC0-f71b-2af1-b9BE4Ac30a16",
+ "name": "ECABG",
+ "description": "ECABG: a Prospective European Multicenter Study on Coronary Artery Bypass Grafting (UK title: A European Study on Coronary Artery Bypass Surgery)",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "ECABG"
+ },
+ {
+ "id": "9b4F2cC6-acb5-E62B-F1e4-47F86B5cECfd",
+ "name": "CardioMEMS HF System OUS Post Approval Study",
+ "description": "CardioMEMS OUS; The purpose of this Post Approval Study (PAS) is to evaluate the use of the CardioMEMS HF System in patients with NYHA Class III (symptoms on mild exertion) Heart Failure in the setting of the NHS.",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "CardioMEMS HF System OUS Post Approval Study"
+ },
+ {
+ "id": "892efC0b-8a5B-6f5C-e7A9-d08aBf52eA17",
+ "name": "SURTAVI (CRN 829)",
+ "description": "CCRN 829 (SURTAVI); Surgical Replacement And Transcatheter Aortic Valve Implantation (SURTAVI)",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "SURTAVI (CRN 829)"
+ },
+ {
+ "id": "2eE10FdB-b63C-F8D6-cdbB-A2BDa059CdE7",
+ "name": "GALILEO",
+ "description": "Global multicenter, open-label, randomized, event-driven, active-controlled study comparing a rivAroxaban-based antithrombotic strategy to an antipLatelet-based strategy after transcatheter aortIc vaLve rEplacement (TAVR) to Optimize clinical outcomes.",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "GALILEO"
+ },
+ {
+ "id": "2a73Ff5d-7014-dB2D-DFf3-C6AFBe130Dac",
+ "name": "ENVISAGE",
+ "description": "EDOXABAN VERSUS STANDARD OF CARE AND THEIR EFFECTS ON CLINICAL OUTCOMES IN PATIENTS HAVING UNDERGONE TRANSCATHETER AORTIC VALVE IMPLANTATION ; Purpose: To assess the effect of Edoxaban versus vitamin K antagonist (VKA) on net adverse clinical events (NAC",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "ENVISAGE"
+ },
+ {
+ "id": "bca5842E-06Cd-E6c2-27bD-D13CfA569e74",
+ "name": "MAP (Movement through Active Personalised engagement)",
+ "description": "Promoting physical activity through group self-management support for those with multi-morbidity: a randomised clinical trial",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "MAP (Movement through Active Personalised engagement)"
+ },
+ {
+ "id": "79C80F4f-fD5F-c85D-b261-2eb4BACc189d",
+ "name": "Format of patient education for different sociodemographic groups",
+ "description": "The influence of socio-demographic characteristics on the preferred format of patient education delivery in individuals; Study administering questionnaires/interviews for quantitative analysis, or using mixed quantitative/qualitative methodology",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "Format of patient education for different sociodemographic groups"
+ },
+ {
+ "id": "eAa53BD9-aFfe-7ac0-9fcD-dc2ae9F15B8C",
+ "name": "DRN 845 LADA",
+ "description": "A study of the Genetic Causes of Latent Autoimmune Diabetes in Adults (LADA); A study of the Genetic Causes of Latent Autoimmune Diabetes in Adults (LADA)",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "DRN 845 LADA"
+ },
+ {
+ "id": "510d6FeD-0bEB-1D52-a0e6-7Dd9acFb8f35",
+ "name": "DRN 763 (Diabetes screening & prevention for people with learning disabilities)",
+ "description": "Screening for glucose intolerance and development of a lifestyle education programme for prevention of Type 2 diabetes in a population with learning disabilities; Screening for glucose intolerance and development of a lifestyle education programme for pr",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "DRN 763 (Diabetes screening & prevention for people with learning disabilities)"
+ },
+ {
+ "id": "CED2b36d-84ab-c852-FC7c-7aDbEBF9532e",
+ "name": "DRN739 (RAMADAN)",
+ "description": "A double blind, double dummy, randomised, multi-centre study to assess the tolerability and efficacy profile of vildagliptin compared to gliclazide as dual therapy with metformin in Muslim patients with type 2 diabetes fasting during Ramadan",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "DRN739 (RAMADAN)"
+ },
+ {
+ "id": "D2aA830d-FAdC-B2ba-0C6F-9eabEc7D62B4",
+ "name": "DRN 709 (PROPELS)",
+ "description": "The Promotion of Physical Activity through structured education with differing levels of ongoing support for those with prediabetes (PROPELS): randomised controlled trial in a diverse multi-ethnic community",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "DRN 709 (PROPELS)"
+ },
+ {
+ "id": "AcECFa8e-3208-B69e-D361-2F1Ea4bBe796",
+ "name": "DRN 663 (Hypoglycaemia in People with Type 2 Diabetes Mellitus in Primary Care)",
+ "description": "Study to Determine the Frequency and Associated Predictors of Hypoglycaemia in People with Type 2 Diabetes Mellitus Managed in Primary Care",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "DRN 663 (Hypoglycaemia in People with Type 2 Diabetes Mellitus in Primary Care)"
+ },
+ {
+ "id": "8ec6E7f2-Da80-fC15-90Ea-fAaF6c0723b8",
+ "name": "Baby Steps - Walking away from Gestational Diabetes",
+ "description": "A randomised controlled trial to investigate the effect of a structured education programme on women who have had gestational diabetes and are at risk of developing type 2 diabetes.; Purpose: To assess the effectiveness of a structured education programme",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "Baby Steps - Walking away from Gestational Diabetes"
+ },
+ {
+ "id": "92b815DF-c41b-E6a3-fdaF-0EFDdcb9624a",
+ "name": "ADDITION - 10 year follow up",
+ "description": "Anglo-Danish-Dutch study of Intensive Treatment of people with Newly diagnosed diabetes in primary care (ADDITION): ten-year follow-up; People with diabetes have an increased risk of developing cardiovascular disease (heart attack or stroke). However, the",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "ADDITION - 10 year follow up"
+ },
+ {
+ "id": "3CAafFe1-bDC0-8f0C-1A96-64cEB1d8aFbA",
+ "name": "3708 CARD e-ULTIMASTER Registry",
+ "description": "Prospective,single-arm, multi-centre, observational registry to further validate safety and efficacy of the ultimaster DES in real-world patients.; The eultimaster registry is an observational study that will collect clinical data on patients with coronar",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "3708 CARD e-ULTIMASTER Registry"
+ },
+ {
+ "id": "37aCAB45-3c06-cC2B-5189-6D52e73bFadC",
+ "name": "Characterising Phenotypes of Mtb Infection (ISIT-TB)",
+ "description": " A Novel Whole Blood Transcriptomic Signature to Characterise Phenotypes of Mycobacterium Tuberculosis Infection (ISIT-TB)",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "Characterising Phenotypes of Mtb Infection (ISIT-TB)"
+ },
+ {
+ "id": "D317Ffa5-9ef4-1f43-fd02-B02ec863bd4E",
+ "name": "CAVALIER",
+ "description": "CAVALIER: Perceval S valve clinical trial for extended CE mark",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "CAVALIER"
+ },
+ {
+ "id": "eEA48cda-dBF1-7baC-dAe9-cF5BefDb16E2",
+ "name": "TMAO levels and CAD Risk",
+ "description": "TMAO levels and CAD Risk; Evaluation of Blood Trimethylamine Acid N-Oxide (TMAO) levels as a risk factor for Coronary Artery Disease (CAD) in South Asians vs. Caucasians",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "TMAO levels and CAD Risk"
+ },
+ {
+ "id": "B40EcAfF-f07e-3e6f-a6F1-CB9cE6Ab3ed0",
+ "name": "Effects of hospitalisation on acute exacerbations of airways disease",
+ "description": "Effects of hospitalisation on acute exacerbations of airways disease; Basic Science study involving procedures with human participants",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "Effects of hospitalisation on acute exacerbations of airways disease"
+ },
+ {
+ "id": "24DE6cbd-b2B1-F267-4c1d-f0A7d3aB895D",
+ "name": "FOAMI",
+ "description": "Investigation of the effect of Myocardial Infarction on Platelet-Induced Monocyte Phenotype and Foam Cell Formation; Does platelet activation due to myocardial infarction (heart attack) lead to changes in monocyte behaviour and render them more able to fo",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "FOAMI"
+ },
+ {
+ "id": "Cad83bfD-6fFD-dBAD-BA63-1db9f75CF403",
+ "name": "Asthma-Tailored Pulmonary Rehabilitation",
+ "description": " A feasibility study to inform the development of a multicentre randomised controlled trial of an asthma-tailored pulmonary rehabilitation programme versus usual care for individuals with severe asthma.",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "Asthma-Tailored Pulmonary Rehabilitation"
+ },
+ {
+ "id": "62D04eab-e251-Cdcb-A6c1-19A5da360eCB",
+ "name": "The effects of reducing prolonged sitting bouts with regular light upright movement breaks on glucose regulation in individuals at high risk of or with type 2 diabetes.",
+ "description": "The effects of reducing prolonged sitting bouts with regular light upright movement breaks on glucose regulation in individuals at high risk of or with type 2 diabetes.; Purpose: To investigate whether the reduction in postprandial plasma glucose in respo",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "The effects of reducing prolonged sitting bouts with regular light upright movement breaks on glucose regulation in individuals at high risk of or with type 2 diabetes."
+ },
+ {
+ "id": "6D3bE8a4-9e67-9Ea1-DB83-eC7FdDfb5c4A",
+ "name": "The PODD Study",
+ "description": " The PODD Study: The PeriOdontal Disease and Diabetes Study: An opportunistic screening study",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "The PODD Study"
+ },
+ {
+ "id": "59Ab01f2-C352-71Cd-0ad8-Fd8C23DA7c6f",
+ "name": "The `Can Do Ramadan' Study",
+ "description": " A Randomised Controlled Trial for People with Established Type 2 Diabetes during Ramadan: Canagliflozin (InvokanaT) vs. standard dual therapy regimen: The `Can Do Ramadan' Study",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "The `Can Do Ramadan' Study"
+ },
+ {
+ "id": "4E0C1DeA-8fEb-3A19-8C63-8B9Df2614E5d",
+ "name": "The 'Arming your Health' study",
+ "description": "Investigating whether breaking up sedentary behaviour with seated upper body contractile activity can regulate an individual's metabolic health",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "The 'Arming your Health' study"
+ },
+ {
+ "id": "FD91b8cA-7EFB-7620-952d-187bac53fB0d",
+ "name": "TEAM GB",
+ "description": "TEAM GB: The Exercise and Gut Bacteria Study",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "TEAM GB"
+ },
+ {
+ "id": "9fE3daF0-8CFd-8adb-FfbD-1b2BAe0EFC6f",
+ "name": "Take Control",
+ "description": "A 24 week, Multicentre, Randomized, Open Label, 2 ARm Parallel-group study evaluating the Efficacy and Safety of Patient - versus Physician-managed Titration of Insulin Glargine U300 in Type 2 Diabetes Mellitus; The purpose of this study is to compare the",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "Take Control"
+ },
+ {
+ "id": "904bfCDB-3f6e-92f1-92E7-42CDB8c19edF",
+ "name": "STRIVE Study",
+ "description": "Effectiveness and cost of integrating a protocol with use of liraglutide 3.0mg into an obesity service (STRIVE Study); The primary objective will be to compare the proportion of participants with severe and complicated obesity (defined as BMI ?35 kg/m2 w",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "STRIVE Study"
+ },
+ {
+ "id": "dBC5fF41-9a0b-6fB1-eE0c-e8A19a5cd7FE",
+ "name": "Sotagliflozin vs. Placebo added to insulin +/- other OADs in T2DM",
+ "description": "A Randomized, Double-blind, Placebo-controlled, Parallel-group, 52-week Multicenter Study to Evaluate the Efficacy and Safety of Sotagliflozin in Patients with Type 2 Diabetes Who Have Inadequate Glycemic Control on Basal Insulin Alone or in Addition to O",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "Sotagliflozin vs. Placebo added to insulin +/- other OADs in T2DM"
+ },
+ {
+ "id": "93DCeF50-84DE-60fc-4e27-cE538feB69D7",
+ "name": "SEESAW",
+ "description": "SGLT2 Inhibitor Empagliflozin Effects on Appetite and Weight Regulation: A randomised double blind placebo controlled trial (SEESAW); Purpose: To determine the effects of empagliflozin on energy expenditure and change in total weight and body composition.",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "SEESAW"
+ },
+ {
+ "id": "ed58DFE3-a621-c71a-fe1B-D0398Abed65F",
+ "name": "PRE-STARt Risk Tool",
+ "description": "PREvention STrategies for Adolescents at Risk of diabetes - validation of a risk tool for young people aged 12 - 14 years;",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "PRE-STARt Risk Tool"
+ },
+ {
+ "id": "728d0a9C-DC9e-f90C-F1Ce-60B3C4FDfA2E",
+ "name": "Pre-Start Phase 2",
+ "description": "Pre-Start Phase 2; Prevention strategies for adolescents at risk of diabetes - A randomised controlled trial of an interactive family-based lifestyle programme",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "Pre-Start Phase 2"
+ },
+ {
+ "id": "91Ce0cAa-513e-0265-6De8-5A2e36890CDf",
+ "name": "Padd",
+ "description": "A multicentre study to investigate the performance of the Padd",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "Padd"
+ },
+ {
+ "id": "405eA7Ea-C7Ff-E0ce-274e-7C9c04651b38",
+ "name": "Physical Activity after Cardiac Events (PACES)",
+ "description": "Developing and evaluating an education programme aimed at increasing physical activity in individuals with diagnosed coronary heart disease: a randomised controlled trial; The main aim of the study is to implement an acceptable and cost-effective educatio",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "Physical Activity after Cardiac Events (PACES)"
+ },
+ {
+ "id": "ba9306cF-Fca6-E3eb-8E5C-5A42e63bFfdD",
+ "name": "Lexicon 310",
+ "description": "A phase 3. randomized, double-blind,placebo-group, multicenter study to evaluate the efficacy, safety, and tolerability of LX4211 as adjunct therapy in adult patients with type 1 diabetes mellitus who have inadequate glycemic control with insulin therapy",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "Lexicon 310"
+ },
+ {
+ "id": "fA8B729a-c718-0e8D-b4f5-ECf45Ba3201A",
+ "name": "IGLOOS",
+ "description": "The impact of glucose lowering therapies including Dipeptidyl peptidase-4 inhibitor on circulating endothelial progenitor cells (EPCs) and its mobilising factor Stromal Derived Factor1; The impact of glucose lowering therapies including Dipeptidyl peptida",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "IGLOOS"
+ },
+ {
+ "id": "b7f430ed-3FAb-F40f-f4De-7fd32Ca1Dc4F",
+ "name": "The effect of a single bout of high-intensity interval training on glucose responses in white European and south Asian patients at risk of type 2 diabetes.",
+ "description": "The effect of a single bout of high-intensity interval training on glucose responses in white European and south Asian patients at risk of type 2 diabetes. Clinical trial to study a novel intervention or randomised clinical trial",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "The effect of a single bout of high-intensity interval training on glucose responses in white European and south Asian patients at risk of type 2 diabetes."
+ },
+ {
+ "id": "9ED3aA26-9306-cf61-FAB1-2b61FC807D3B",
+ "name": "Girls Active",
+ "description": "n/a",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "Girls Active"
+ },
+ {
+ "id": "ADe7d084-Ffbe-B4CE-C2bd-34E78e92cD0B",
+ "name": "Exploring views and evaluating a web-based intervention",
+ "description": "Exploring the views of people with type 2 diabetes and healthcare professionals on web-based interventions that aim to improve wellbeing in type 2 diabetes and evaluating the final design of a web-based intervention.; Purpose: To explore the views of peop",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "Exploring views and evaluating a web-based intervention"
+ },
+ {
+ "id": "C8e476Fa-b0c5-7db9-62a7-52Ac813F7daB",
+ "name": "Evaluating the goal setting session of DESMONd V1",
+ "description": "Process and outcome evaluation of the goalsetting compenent of a type 2 diabetes group self-management programme; Assessing the goal setting component of DESMOND, a structured diabetes self management education(DSME) programme for people newly diagnosed.",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "Evaluating the goal setting session of DESMONd V1"
+ },
+ {
+ "id": "8E9d357D-63E2-0Fed-31FD-f5Ad63e1Ca87",
+ "name": "Embedding Diabetes Education - (RCT)",
+ "description": "Evaluating the impact of an intervention to increase uptake of self-management education programmes for Type 2 Diabetes in primary care: A wait-list cluster randomised controlled trial; The Embedding Package is designed to increase uptake in primary care",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "Embedding Diabetes Education - (RCT)"
+ },
+ {
+ "id": "961d4Ef7-DE2F-cF3b-39eF-BC5291e7b4F6",
+ "name": "Embedding Diabetes Education (Feasibility study)",
+ "description": "Increasing uptake of self-management education programmes for Type 2 Diabetes in multi-ethnic primary care settings: A feasibility study ; Purpose: To implement an Embedding Package to increase the uptake to self-management education programmes for type ",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "Embedding Diabetes Education (Feasibility study)"
+ },
+ {
+ "id": "36ae82B4-9d8c-af53-E7Fa-B7e03Db8529C",
+ "name": "DRN2710 (AWARD-9)",
+ "description": "A Randomized, Double-Blind Trial Comparing the Effect of Dulaglutide 1.5 mg with Placebo on Glycemic Control in Patients with Type 2 Diabetes on Basal Insulin Glargine (AWARD-9: Assessment of Weekly AdministRation of LY2189265 in Diabetes – 9)",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "DRN2710 (AWARD-9)"
+ },
+ {
+ "id": "94b678e5-64E9-1eFE-D6e0-EF8CDfA97B20",
+ "name": "DRN2661 (LixiLan-O)",
+ "description": "A randomized, 30 week, active-controlled, open-label, 3-treatment arm,parallel-group multicenter study comparing the efficacy and safety of insulinglargine/ lixisenatide fixed ratio combination to insulin glargine and lixisenatide alone on top of metformi",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "DRN2661 (LixiLan-O)"
+ },
+ {
+ "id": "eDE82073-41ec-28F5-E162-bCA782e3Da04",
+ "name": "DRN2650 (210225)",
+ "description": "A Phase 3, Randomized, Double-Blind, Placebo-Controlled, 26 Week Multicenter Study With A 26-Week Extension To Evaluate The Efficacy And Safety Of Ertugliflozin Monotherapy In The Treatment Of Subjects With Type 2 Diabetes Mellitus And Inadequate Glycemic",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "DRN2650 (210225)"
+ },
+ {
+ "id": "dD475fbc-E2CF-0e16-810D-9Be3cD16aA8E",
+ "name": "DRN2487 (CANVAS-R)",
+ "description": "A Randomised, Multi-Centre, Double-Blind, Parallel, Placebo-Controlled Study of the Effects of Canagliflozin on Renal Outcomes in Adult Subjects with Type 2 Diabetes Mellitus",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "DRN2487 (CANVAS-R)"
+ },
+ {
+ "id": "FbE27deB-A8e7-fBA6-7056-fcE9FDC3582A",
+ "name": "DRN2373 (CARMELINA)",
+ "description": "A multicenter, international, randomized, parallel group, double blind, placebo-controlled CArdiovascular Safety & Renal Microvascular outcomE with LINAgliptin, 5 mg once daily in patients with type 2 diabetes mellitus at high vascular risk. CARMELINA",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "DRN2373 (CARMELINA)"
+ },
+ {
+ "id": "3f781Ce9-e4ca-a01C-deCB-61EFae05B79A",
+ "name": "DRN2312",
+ "description": "Multiple dose trial examining dose range, escalation and efficacy of oral semaglutide (NNC0113-0217) in subjects with type 2 diabetes",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "DRN2312"
+ },
+ {
+ "id": "fE08a235-E084-D1ea-2f0c-c1FDE32C8f45",
+ "name": "DRN2292 (GWDM1302)",
+ "description": "A randomised, double blind, placebo controlled, parallel group, dose ranging study of GWP42004 as add on to metformin in the treatment of participants with Type 2 diabetes",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "DRN2292 (GWDM1302)"
+ },
+ {
+ "id": "EdCe39A0-D4b0-e2ac-Ab7a-B2Eceb4Ca0fF",
+ "name": "DRN 826 LYDIA study",
+ "description": "Impact of liraglutide on cardiac function and structure in young adults with type 2 diabetes: an open lable, randomised active-comparator trial (LYDIA); Impact of liraglutide on cardiac function and structure in young adults with type 2 diabetes: an open ",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "DRN 826 LYDIA study"
+ },
+ {},
+ {
+ "id": "6c9F8Db0-fcEe-7df0-DAbB-92dbF0C5D876",
+ "name": "DRN 780 (INFLAME)",
+ "description": "DRN 780 (INFLAME); A comparison of subcutaneous and visceral adipose tissue inflammation in South Asian and white European men",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "DRN 780 (INFLAME)"
+ },
+ {
+ "id": "d20976Ee-40E7-9b4a-0B63-38bDF16fcEBd",
+ "name": "DRN706 (GETGOAL DUO-2)",
+ "description": "A randomized, open-label, active-controlled, 3-arm parallel-group, 26-week study comparing the efficacy and safety of lixisenatide to that of insulin glulisine once daily and insulin glulisine three times daily in patients with Type 2 diabetes insufficien",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "DRN706 (GETGOAL DUO-2)"
+ },
+ {
+ "id": "f10Aa4Bd-71C2-f2bE-87Cc-E61Fec85f9aD",
+ "name": "DRN 679 (DESMOND-Ongoing Study)",
+ "description": "To test an integrated approach for promoting effective selfmanagement in people with established Type 2 Diabetes Mellitus (T2DM) ",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "DRN 679 (DESMOND-Ongoing Study)"
+ },
+ {
+ "id": "2b4961E0-d87a-3e94-Af40-D76c18a29504",
+ "name": "DRN 678 (DESMOND Foundation Study)",
+ "description": "A randomised controlled trial of the DESMOND Foundation programme for people with established Type 2 diabetes in a multiethnic population in Leicester and South Birmingham",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "DRN 678 (DESMOND Foundation Study)"
+ },
+ {
+ "id": "D6fc8a90-3485-Df0e-aceC-D56074A8c3bC",
+ "name": "DRN 668 (SUCCESS - Interviews sub-study)",
+ "description": "Structured Education Programme to Improve Cardiovascular Risk in Women with Polycistic Ovary Syndrome - Interviews sub-study",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "DRN 668 (SUCCESS - Interviews sub-study)"
+ },
+ {
+ "id": "ab15F32C-eB7A-49df-A6ec-b7Cf5aE91D4c",
+ "name": "DRN 667 (SUCCESS RCT sub-study)",
+ "description": "StructUred eduCation programme to improve Cardiovascular Risk in womEn with polycyStic ovary Syndrome - RCT sub-study",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "DRN 667 (SUCCESS RCT sub-study)"
+ },
+ {
+ "id": "deD57093-baEf-B95E-3eCA-2c61De8Bb0fF",
+ "name": "DRN 650 (SUCCESS study)",
+ "description": "StructUred eduCation programme to improve Cardiovascular Risk in womEn with polycyStic ovary Syndrome",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "DRN 650 (SUCCESS study)"
+ },
+ {
+ "id": "b2aD5A07-De21-e869-Bb94-2A8F465EBD7f",
+ "name": "DRN 640 (SWEET-Heart study)",
+ "description": "Screening White Europeans and Ethnic South Asians for glucose intolerence following heart attack (The SWEET-Heart study)",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "DRN 640 (SWEET-Heart study)"
+ },
+ {
+ "id": "E97A8aB5-62F3-934d-74AB-fEc1dba6958C",
+ "name": "DRN 626",
+ "description": "Efficacy and safety of liraglutide versus placebo as add-on to existing diabetes medication in subjects with type 2 diabetes and moderate renal impairment; A 26-week double-blind placebo-controlled, randomised, multicentre, multi-national, parallel-group ",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "DRN 626"
+ },
+ {
+ "id": "A9853aDC-bFEe-F853-BEbc-2a98F1DBEcb5",
+ "name": "DRN622 (The IMAGINE 4 Study)",
+ "description": "The Impact of LY2605541 versus Insulin Glargine for Patients with Type 2 Diabetes Mellitus Advanced to Multiple Injection Bolus Insulin with Insulin Lispro: a Double-Blind, Randomized, 26 Week Study: The IMAGINE-4 Study",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "DRN622 (The IMAGINE 4 Study)"
+ },
+ {
+ "id": "B28c3fa6-B947-7a02-aA8E-d51FeD04bf3a",
+ "name": "DRN621 (The IMAGINE 3 Study)",
+ "description": "The Impact of LY2605541 versus Insulin Glargine for Patients with Type 1 Diabetes Mellitus Treated with Preprandial Insulin Lispro: a Double-Blind, Randomized, 52 Week Study: The IMAGINE-3 Study",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "DRN621 (The IMAGINE 3 Study)"
+ },
+ {
+ "id": "e83da1b7-d589-FEd8-A96D-C5F9AfdEe683",
+ "name": "DRN 608 (VITALITY)",
+ "description": "Can Vitamin D Replacement Reduce Insulin resistance In South Asians with Vitamin D Deficiency?; This study will test the hypothesis that 6 months of periodic high dose Vitamin D3 replacement (200,000 and 100,000 units cholecalciferol, oral liquid drops at",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "DRN 608 (VITALITY)"
+ },
+ {
+ "id": "F14f5dCB-14a6-20D9-4b38-B6bC0F73eDdE",
+ "name": "DRN594 (The IMAGINE-2 Study)",
+ "description": "A Comparison of LY2605541 Versus Insulin Glargine as Basal Insulin Treatment in Combination with Oral Anti-Hyperglycemia Medications in Insulin Na",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "DRN594 (The IMAGINE-2 Study)"
+ },
+ {
+ "id": "f4Bb12a9-C3E1-cCf7-fF31-5ab2CcdB604f",
+ "name": "DRN556 (Treat 4 Ramadan)",
+ "description": "TREAT 4 Ramadan. A Randomised Controlled Trial for People with Established Type 2 Diabetes during Ramadan Liraglutide vs. a Sulphonylurea or Pioglitazone",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "DRN556 (Treat 4 Ramadan)"
+ },
+ {
+ "id": "d4fa32eE-9e47-0FB4-1Fc7-AFB801C2375b",
+ "name": "DRN464",
+ "description": "An extension trial to NN1250-3585 (DRN356) investigating safety and efficacy of NN1250 compared to insulin detemir in subjects with type 1 diabetes mellitus in a basal/bolus treatment regimen",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "DRN464"
+ },
+ {
+ "id": "fC7Db3ce-69ef-9eA5-ACcF-C4F31ac8EA9B",
+ "name": "DRN305",
+ "description": "A randomised, multicenter, double-blind, parallel, placebo-controlled study of the effects of JNJ-28431754 on cardiovascular outcomes in adult subjects with type 2 diabetes subjects with type 2 diabetes mellitus; A randomised, multicenter, double-blind, ",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "DRN305"
+ },
+ {
+ "id": "E4edC52B-Edac-ba40-Dc6b-0fdcB3D64ab2",
+ "name": "DRN251 (TECOS)",
+ "description": "A Randomized, Placebo Controlled Clinical Trial to Evaluate Cardiovascular Outcomes after Treatment with Sitagliptin in Patients with Type 2 Diabetes Mellitus and Inadequate Glycemic Control; This is a clinical trial designed to assess the cardiovascular ",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "DRN251 (TECOS)"
+ },
+ {
+ "id": "df826BAE-2cdb-65D8-2A7B-35bdCD8Ace46",
+ "name": "DRN 239 LETS PREVENT",
+ "description": "A community based primary prevention programme for Type 2 Diabetes integrating identification, lifestyle intervention and community services for prevention (RCT). N.B-this is part of a programme grant award which is the same NIHR programme grant as DRN131",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "DRN 239 LETS PREVENT"
+ },
+ {
+ "id": "Aac78419-CbF2-58E1-B029-67BdEA41F8a2",
+ "name": "DRN108 (Genetics of Type 2 Diabetes in Multi-Ethnic populations)",
+ "description": "A DNA resource to facilitate the investigation of genetic susceptibility to Type 2 Diabetes and its microvascular/macrovascular complications in the UK-resident South Asians",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "DRN108 (Genetics of Type 2 Diabetes in Multi-Ethnic populations)"
+ },
+ {
+ "id": "3DA78c49-1dEb-f0B6-538D-fa234e1DEd9B",
+ "name": "DRN 094 (ADDRESS)",
+ "description": "After Diagnosis Diabetes Research Support System",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "DRN 094 (ADDRESS)"
+ },
+ {
+ "id": "FDC0E7A5-Fe67-6abF-05fD-8ebA64d5F310",
+ "name": "DRN 022 ADDITION-Leicester (LRN SEM)",
+ "description": "A randomised trial of the cost effectiveness of screening and intensive multi-factorial intervention for Type 2 diabetes - The ADDITION-Leicester study; Purpose: To assess the fesibilty of screening and multi-factorial intensive intervention in ethnic min",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "DRN 022 ADDITION-Leicester (LRN SEM)"
+ },
+ {
+ "id": "9c6EA20B-BF39-FcDA-C1D0-3c78Fa5dE16D",
+ "name": "DIAB 5013",
+ "description": "A real-world, point of care, randomized, 2-arm, open, 52-week study to evaluate the effect of a digital disease management support tool in patients with type 2 diabetes mellitus; Purpose: To evaluate the effect of a smart phone- and web portal-based digit",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "DIAB 5013"
+ },
+ {
+ "id": "c9e5A4d2-Cc2D-498c-daD4-b45196E0a3BC",
+ "name": "DIAB 4831",
+ "description": "Efficacy and long-term safety of oral semaglutide versus sitagliptinin subjects with type 2 diabetes; NN99244222 is a randomised, doubleblind, doubledummy, active controlled, parallelgroup, multicentre, multinational, fourarmed study comparing the e",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "DIAB 4831"
+ },
+ {
+ "id": "dC5F03c8-AB6E-0D86-fEC2-EC65Bf793ca2",
+ "name": "DIAB 4826",
+ "description": "A Phase 3, Randomized, Double-blind, Placebocontrolled, Parallel-group, Multicenter Study to Evaluate the Net Clinical Benefit of Sotagliflozin as Adjunct to Insulin Therapy in Type 1 Diabetes; ",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "DIAB 4826"
+ },
+ {
+ "id": "Bab57fCA-Adb8-1f24-FE4A-dF14e53c9AB2",
+ "name": "DIAB 4389",
+ "description": "A Phase III, randomised, double blind, placebo-controlled,parallel group, efficacy, safety and tolerability trial of once daily, oral doses of Empagliflozin as Adjunctive to inSulin thErapy over 26 weeks in patients with Type 1 Diabetes Mellitus (EASE-3)",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "DIAB 4389"
+ },
+ {
+ "id": "Efbc8a7e-bca1-c0EA-Fe1A-5EF92bA831f6",
+ "name": "DIAB 3771",
+ "description": "A Phase III, randomised, double blind, placebo-controlled, parallel group, efficacy, safety and tolerability trial of Empagliflozin as Adjunctive to insulin over 52 weeks in patients with Type 1 DiabeteS MEllitus (EASE-2)",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "DIAB 3771"
+ },
+ {
+ "id": "0Fda5eA9-01ae-C0Aa-E4Ab-8f567A0CecD4",
+ "name": "Declining structured diabetes education",
+ "description": "Exploring patients with Type 1 diabetes lack of engagement with structured diabetes education in order to enhance future service provision; Structured diabetes education (SDE) is widely regarded as the cornerstone of effective self-management. Current ap",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "Declining structured diabetes education"
+ },
+ {
+ "id": "10aefbE8-7cA6-d43f-2d8b-e26EAd790F85",
+ "name": "Chronotype of Patients with Type 2 Diabetes and Effect on Glycaemic Control: The CODEC Study",
+ "description": " To investigate whether an evening-chronotype is associated with higher levels of HbA1c in those with established T2DM compared to a morning-chronotype, as defined by the composite morningness scale (CMS)",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "Chronotype of Patients with Type 2 Diabetes and Effect on Glycaemic Control: The CODEC Study"
+ },
+ {
+ "id": "b0FBa6cf-cdfC-DEbc-8eE1-deB31b9CFaA8",
+ "name": "A Safer Ramadan",
+ "description": "Evaluating the Impact and Acceptability of 'A Safer Ramadan' Education Programme: a structured approach that addresses safer observance of Ramadan in Muslim patients with Type 2 diabetes; Interviews have been carried out with various stakeholders involved",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "A Safer Ramadan"
+ },
+ {
+ "id": "ef1E50Ca-fB01-afA5-b803-3d24CaeE5Db7",
+ "name": "Are metabolic responses to sitting/light breaks mediated by fitness?",
+ "description": "n/a",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "Are metabolic responses to sitting/light breaks mediated by fitness?"
+ },
+ {
+ "id": "E7e8d3Ff-87AE-5AC8-416b-8BdA09Fa4b1C",
+ "name": "BASIL-3",
+ "description": "Multi-centre randomised controlled trial of clinical and cost-effectiveness of drug coated balloons, drug eluting stents and plain balloon angioplasty with bail-out bare metal stent revascularisation strategies for severe limb ischaemia due to atheroscler",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "BASIL-3"
+ },
+ {
+ "id": "f2E1Ad3F-8C4E-a4cC-16AC-FE3C12eB59c0",
+ "name": "BASIL-2",
+ "description": "Bypass vs. Angioplasty in Severe Ischaemia of the Leg-2 (BASIL-2); Multi-centre randomised controlled trial to compare the clinical and cost-effectiveness of a `vein bypass first' with a `best endovascular first' revascularisation strategy for severe lim",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "BASIL-2"
+ },
+ {
+ "id": "6b8fEAd5-25C6-92f7-AcB8-e42F79ab58d3",
+ "name": "Analysis of peripheral blood ILC2s/Th2 cells in response to ANB020",
+ "description": "Analysis of peripheral blood ILC2s/Th2 cells in response to ANB020; Purpose: To investigate whether treatment with ANB020, a drug that targets IL-33 (an inflammatory mediator in asthma) alters levels of Basophils, Th2 cells or innate lymphoid type 2 cells",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "Analysis of peripheral blood ILC2s/Th2 cells in response to ANB020"
+ },
+ {
+ "id": "C917Bb4e-D0Ae-c3CB-c1F8-46df0e17D5C9",
+ "name": "CYCLE-HD",
+ "description": "CYCLE-HD: Improving cardiovascular health in dialysis patients using a structured programme of exercise.; Purpose: To investigate the effect of a six month programme of intradialytic exercise on cardiovascular structure and function.",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "CYCLE-HD"
+ },
+ {
+ "id": "e5D604cC-f5DC-aF5B-a40C-B3a2fCebF701",
+ "name": "DRN516",
+ "description": "A Phase 2, randomised, double-blind, placebo-controlled, parallel group, multi-center study to evaluate the efficacy and safety of once-daily administration of phosphodiesterase 5 inhibitor (PF-00489791) in adults with type 2 diabetes and overt nephropat",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "DRN516"
+ },
+ {
+ "id": "e8D42a5c-7B52-67da-5796-7456Bbd3C0fE",
+ "name": "VOLCANO-2",
+ "description": "A DOUBLE-BLIND, RANDOMISED, PLACEBO CONTROLLED STUDY OF THE EFFICACY AND SAFETY OF THREE DOSES OF ORVEPITANT IN PATIENTS WITH CHRONIC REFRACTORY COUGH",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "VOLCANO-2"
+ },
+ {
+ "id": "708e1962-FE6B-7946-4Ced-208BAEedf1C5",
+ "name": "Study to evaluate a mepolizumab autoinjector in severe asthma",
+ "description": "An open-label, single arm, repeat dose, multi-centre study to evaluate the use of an autoinjector for the subcutaneous administration of mepolizumab in subjects with severe eosinophilic asthma",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "Study to evaluate a mepolizumab autoinjector in severe asthma"
+ },
+ {
+ "id": "A1Ecd8Fb-7dBc-5B7a-4309-CB698adc3A15",
+ "name": "SoMOSA: Study of Mechanisms of Action of Omalizumab in Severe Asthma.",
+ "description": "SoMOSA: Study of Mechanisms of Action of Omalizumab in Severe Asthma",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "SoMOSA: Study of Mechanisms of Action of Omalizumab in Severe Asthma."
+ },
+ {
+ "id": "bd120e6A-50EF-f6Ce-E8ef-174FDEabdCce",
+ "name": "RESP 5262",
+ "description": "AF219-012: A 12-Week Study to Assess the Efficacy and Safety of AF-219 in Subjects with Treatment Refractory Chronic Cough",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "RESP 5262"
+ },
+ {
+ "id": "8D5Af146-fF2B-CbE3-B83b-eb1Bf20EAdD5",
+ "name": "RESP 4446",
+ "description": "A 52-week, multicenter, randomized, double-blind, placebo-controlled study to assess the efficacy and safety of QAW039 when added to existing asthma therapy in patients with uncontrolled severe eosinophilic asthma",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "RESP 4446"
+ },
+ {
+ "id": "179A30E5-dD52-D9f8-EfbD-97EA48eFd6a0",
+ "name": "RESP 3808 (Asthma)",
+ "description": "Phase 2, randomized, double-blind, placebo-controlled, parallel-group study to assess the efficacy, safety, and pharmacokinetics of BI 655066, compared to placebo, administered subcutaneously in patients with uncontrolled severe asthma.",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "RESP 3808 (Asthma)"
+ },
+ {
+ "id": "Cfb2e03A-Ba18-EB5c-C8A3-DE861edA549B",
+ "name": "RESP 3600 (Asthma)",
+ "description": "A 52-week, multicentre,randomised, double-blind, parallel group, placebo controlled, phase 3 study to evaluate the efficacy and safety of tralokinumab in adults and adolescents with asthma inadequately controlled on inhaled corticosteroids plus long-actin",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "RESP 3600 (Asthma)"
+ },
+ {
+ "id": "d2F48efE-8DFA-3Df0-82ae-5f3aCeBA6d14",
+ "name": "Exploring Asthma Exacerbation in Mepolizumab Treated Patients",
+ "description": "Exacerbation Profile in Patients on Mepolizumab for Severe Refractory Eosinophilic Asthma - an Exploratory Study",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "Exploring Asthma Exacerbation in Mepolizumab Treated Patients"
+ },
+ {
+ "id": "1fe0dC93-6fFA-1793-FbEd-93b25d4AECD8",
+ "name": "Evaluation of sputum MMP9 in COPD subject",
+ "description": "A Translational Multicenter Study to Evaluate Sputum MMP9 Levels and Enzyme Activity in Subjects with Chronic Obstructive Pulmonary Disease(COPD) Compared to Matched Healthy Controls",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "Evaluation of sputum MMP9 in COPD subject"
+ },
+ {
+ "id": "d1E7CA2D-Fa9e-DEd6-cD74-678352Ad0eE1",
+ "name": "Effect of Tralokinumab on Airway Inflammation in Asthma",
+ "description": " A Multicentre, Randomized, Double-blind, Parallel Group, Placebo Controlled, 12-Week, Phase 2 Study to Evaluate the Effect of Tralokinumab on Airway Inflammation in Adults with Asthma Inadequately Controlled on Inhaled Corticosteroid (MESOS)",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "Effect of Tralokinumab on Airway Inflammation in Asthma"
+ },
+ {
+ "id": "f731E54D-20eB-Fe1c-28E4-f7Bd9bFc082E",
+ "name": "An exploratory, prospective, non-interventional study comparing biomarker signatures between patients with asthma and healthy volunteers and to investigate biomarkers associated with known phenotypes across asthma severities.",
+ "description": "Cognosco 352.2087: An exploratory, prospective, non-interventional study comparing biomarker signatures between patients with asthma and healthy volunteers and to investigate biomarkers associated with known phenotypes across asthma severities.",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "An exploratory, prospective, non-interventional study comparing biomarker signatures between patients with asthma and healthy volunteers and to investigate biomarkers associated with known phenotypes across asthma severities."
+ },
+ {
+ "id": "906dB8A2-b4A0-dDa2-aC2D-2e5B47c9FA6D",
+ "name": "CCRN 2873 (COPD)",
+ "description": "A randomised, double-blind, placebo-controlled, parallel group, multicentre, phase III study to evaluate the efficacy and safety of 2 doses of benralizumab (MEDI-563) in patients with severe to very severe Chronic Obstructive Pulmonary Disease (COPD) with",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "CCRN 2873 (COPD)"
+ },
+ {
+ "id": "091F3Cc7-8b9E-d8DC-27bE-8547e2E6BAC9",
+ "name": "CCRN 2856 (COPD)",
+ "description": "A Phase II, randomised, observer-blind, placebocontrolled, multi-centre study to evaluate the safety,reactogenicity and immunogenicity of GSK Biologicals",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "CCRN 2856 (COPD)"
+ },
+ {
+ "id": "90182eBD-306c-a7Bb-BE27-16f74cBd2E89",
+ "name": "Bronchial Thermoplasty Study",
+ "description": "An observational study examining airway remodelling and repair in patients with severe persistent asthma treated with bronchial thermoplasty: An imaging and immunopathological study",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "Bronchial Thermoplasty Study"
+ },
+ {
+ "id": "E5B38Abc-F5Cb-CE01-D31e-96aeD3c4f78b",
+ "name": "BI 352.2069",
+ "description": "Emphysema Progression Biomarker Study - Observational study in healthy subjects and patients with COPD to assess the relationship between clinical, imaging and biomarker measurements, and progression of emphysema over two years.",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "BI 352.2069"
+ },
+ {
+ "id": "5e670cDd-A0C9-0FCe-CBd3-feaD68A1dE5c",
+ "name": "Asthma/COPD III",
+ "description": "An open study to measure inflammatory cells, mediators and biomarkers from blood and sputum from healthy volunteers and asthma patients and blood, sputum and urine from COPD patients in stable disease and during acute exacerbations",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "Asthma/COPD III"
+ },
+ {
+ "id": "D548e3E0-8CbE-DEcC-6FdD-0ACa26cE8eFB",
+ "name": "Airway inflammation in asthma (DAC)",
+ "description": "The value of measuring airway inflammation in the management of asthma",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "Airway inflammation in asthma (DAC)"
+ },
+ {
+ "id": "C07d2aB6-CB67-38ec-5acb-472CfBea196b",
+ "name": "RASP Bronchoscopy Study",
+ "description": "Refractory Asthma Stratification Programme (RASP) Bronchoscopy Study; The principal research question is therefore: What are the molecular mechanisms that drive severe asthma in patients who do not have evidence of Th2 cytokine expression?",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "RASP Bronchoscopy Study"
+ },
+ {
+ "id": "518dB0A9-A450-abdc-c8Dd-28A0B1Ddcf9a",
+ "name": "Laminar Airflow in Severe Asthma for Exacerbation Reduction - LASER",
+ "description": "A multi-centre randomised, double blind, placebo-controlled, parallel group trial of the effectiveness of the nocturnal use of a Temperature Controlled Laminar Airflow (TLA) Device (Airsonett; Asthma affects over 5 million patients in the UK. Half a milli",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "Laminar Airflow in Severe Asthma for Exacerbation Reduction - LASER"
+ },
+ {
+ "id": "Ee43CbBF-3eA0-eE4D-2D3b-850F6fEdABec",
+ "name": "Genetic causes of chronic cough and neuropathy",
+ "description": "Genetic causes of chronic cough and neuropathy;",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "Genetic causes of chronic cough and neuropathy"
+ },
+ {
+ "id": "4c3E8DAF-64FD-245c-C9ae-fd0148D9C3BA",
+ "name": "Gene profiling in asthma",
+ "description": "Gene expression profiling in mild and severe asthma, eosinophilic bronchitis, and normal controls; ",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "Gene profiling in asthma"
+ },
+ {
+ "id": "97fF26AD-FB38-Cdb9-FC7b-6B7Fe91cEd2a",
+ "name": "Gene expression profiling in asthma",
+ "description": "A randomised, open-labelled bronchoscopy study to assess the effects of inhaled corticosteroid (ICS) on adult healthy volunteers; Asthma is a very common disorder which causes a great deal of distress for sufferers, and occasionally results in premature d",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "Gene expression profiling in asthma"
+ },
+ {
+ "id": "AaD82B6d-e739-6341-be4f-62093eCd1F54",
+ "name": "GB29260 Lebrikizumab in patients with uncontrolled asthma",
+ "description": "A Phase II, Randomised, Double Blind, Placebo-controlled Bronscoscopy study to evaluate the effects of Lebrikizumab on airway eosinophilic inflammation in patients with uncontrolled asthma on inhaled corticosteroids and a second controller medication.; St",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "GB29260 Lebrikizumab in patients with uncontrolled asthma"
+ },
+ {
+ "id": "D974c5ae-9854-495e-963c-cE0549f7A8CB",
+ "name": "A pragmatic trial of corticosteroid optimisation in severe asthma",
+ "description": "A RANDOMISED PRAGMATIC TRIAL OF CORTICOSTEROID OPTIMISATION IN SEVERE ASTHMA USING A COMPOSITE BIOMARKER ALGORITHM TO ADJUST CORTICOSTEROID DOSE VERSUS STANDARD CARE",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "A pragmatic trial of corticosteroid optimisation in severe asthma"
+ },
+ {
+ "id": "c6D4be1A-BE34-3c18-9713-5fe0Bc12CFaA",
+ "name": "UK CAVIAR",
+ "description": "The UK CArdiac And Vascular Surgery Interventional Anaemia Response Study: An Observational Cohort Study To Determine The Impact And Effect Of Anaemia In Patients Awaiting Vascular And Cardiac Surgery.; This is a multicentre centre, observational pilot st",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "UK CAVIAR"
+ },
+ {
+ "id": "7D9bF58f-7e9E-31ac-A68f-01CE65b9eaBd",
+ "name": "HYDRA-P",
+ "description": "HYDration and bicarbonate to prevent acute Renal injury after endovascular Aneurysm repair",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "HYDRA-P"
+ },
+ {
+ "id": "2D6fEC5e-94EA-DEeb-da3B-fFe3b216Cc74",
+ "name": "LuCID: Lung Cancer Indicator Detection",
+ "description": "LuCID: Lung Cancer Indicator Detection; Purpose: Rationale Early detection of lung cancer is of paramount importance to improve patient outcome. Unfortunately most early stage tumors are asymptomatic. At this stage cancer cells do already have considerab",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "LuCID: Lung Cancer Indicator Detection"
+ },
+ {
+ "id": "0D982f1E-2f8b-a72b-5B0f-d9E0B37264aF",
+ "name": "CCRN 2536 (Idiopathic pulmonary fibrosis)",
+ "description": "PASSPORT - Post-Authorisation Safety Study (PASS) of Esbriet (Pirfenidone): A Prospective Observational Registry to Evaluate Long-Term Safety in a Real-World Setter",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "CCRN 2536 (Idiopathic pulmonary fibrosis)"
+ },
+ {
+ "id": "2a751f8F-aed8-dFf5-AFdB-6128e53c4ABf",
+ "name": "VICORI",
+ "description": "Cardio-oncology: A high resolution national electronic health record investigation of the interplay between cancer and heart disease ; Purpose: To investigate the interactions between heart disease and cancer.",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "VICORI"
+ },
+ {
+ "id": "c2DB8FAE-7Eb0-7fAE-2950-360a2c81Bd9f",
+ "name": "TICONC",
+ "description": "Ticagrelor for prevention of tumour cell-induced platelet aggregation; Purpose: Investigating Aspirin and Ticagrelor for the prevention of tumour cell-induced platelet aggregation",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "TICONC"
+ },
+ {
+ "id": "29AaEd4e-B254-75FE-deA0-aCB198b53E46",
+ "name": "SCAD CAE",
+ "description": "Rare coronary phenotypes leading to acute coronary syndromes (ACS): A deep phenotyping study of spontaneous; A deep phenotyping study of spontaneous coronary artery dissection (SCAD) and coronary artery aneurysms/ectasia (CAE)",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "SCAD CAE"
+ },
+ {
+ "id": "8Ba26db3-d4Be-3560-6D89-b6DB41f297aF",
+ "name": "GLOBAL LEADERS",
+ "description": "Global Leaders (ECRI 1) (CCRN 2137); Comparative effectiveness of 1 month of ticagrelor plus aspirin followed by ticagrelor monotherapy versus a current day intensive dual anitplatelet therapy in all comers patients undergoing percutaneous coronary inter",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "GLOBAL LEADERS"
+ },
+ {
+ "id": "E693CD41-2A1e-8147-CAE5-E2cb5Af6e31a",
+ "name": "Faraday 5301-201",
+ "description": "Phase 2A, Randomized, Double-Blind, Placebo-Controlled, Multi-Center Study of Intravenous FDY-5301 in Acute Myocardial Infarction (Protocol No. FDY-5301-201)",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "Faraday 5301-201"
+ },
+ {
+ "id": "87653cfE-07fA-467C-3F91-0aEc2De8Bf35",
+ "name": "Epidemiology, management, outcomes and pathophysiology of SCAD",
+ "description": "Epidemiology, management, outcomes and pathophysiology of SCAD; Spontaneous coronary artery dissection (SCAD): vascular pathophysiology, epidemiology and genetics",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "Epidemiology, management, outcomes and pathophysiology of SCAD"
+ },
+ {
+ "id": "DAd1fB20-A4eF-b74c-A69a-dBe2bE6Daf5A",
+ "name": "A Feasibility Study of Coronary OCT Correlation and Strain Mapping",
+ "description": "A Feasibility Study of Coronary OCT Correlation and Strain Mapping; Coronary optical coherence tomography correlation and strain mapping to investigate human atherosclerosis: a feasibility study.",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "A Feasibility Study of Coronary OCT Correlation and Strain Mapping"
+ },
+ {
+ "id": "271ad065-F6dB-2fce-abdf-7231ef64bcE8",
+ "name": "ABSORB UK Registry",
+ "description": "A post-market registry of patients with de novo lesions in previously untreated vessels treated with Absorb BVS; Prospective multi-center registry evaluating the safety and clinical outcomes of the Absorb BVS in daily use in patients with de novo lesions ",
+ "externalUrl": "https://www.le.ac.uk/",
+ "createDateTime": "2022-08-02 11:56:54",
+ "updateDateTime": "2022-08-02 11:56:54",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "ABSORB UK Registry"
+ },
+ {
+ "id": "7c84dBF5-dCB6-94Ee-4d29-7Cf8E90D563c",
+ "name": "REVAKI-2",
+ "description": "In a double-blind RCT, adults at increased risk of AKI undergoing cardiac surgery were randomised to receive sildenafil citrate or dextrose at the commencement of surgery. The primary outcome was serum creatinine. The primary analysis used a linear mixed-effects model adjusted for the stratification variables, baseline eGFR, and surgical procedure. Secondary outcomes considered clinical events and potential disease mechanisms. Effect estimates were expressed as MDs or odds ratios with 95% CI.",
+ "externalUrl": "https://www2.le.ac.uk/departments/cardiovascular-sciences/people/murphy",
+ "createDateTime": "2022-04-07 15:29:49",
+ "updateDateTime": "2022-04-07 15:29:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "6d031B9D-1cbC-be8F-83fC-A79B1ed4802a",
+ "name": "Salmonella phage ΦRA collection",
+ "description": "Phage collection targeting multiple serovars of Salmonella ",
+ "externalUrl": "https://le.ac.uk/research/luminaries/professor-martha-clokie",
+ "createDateTime": "2021-11-29 17:15:19",
+ "updateDateTime": "2021-11-29 17:15:19",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "B49DA01e-CB59-3CB4-963E-b83a1024D5fF",
+ "name": "Detailed characterisation of clinically relevant Clostridioides difficile phages",
+ "description": "The microbiome dysbiosis caused by antibiotic treatment has been associated with both susceptibility to and relapse of Clostridioides (formerly Clostridium) difficile infection (CDI). Bacteriophage (phage) therapy offers target specificity and dose amplification in situ, but few studies have focused on its use in CDI treatment. This mainly reflects the lack of strictly virulent phages that target this pathogen. This project focuses on the development of seven broad host range phages ",
+ "externalUrl": "https://le.ac.uk/research/luminaries/professor-martha-clokie",
+ "createDateTime": "2021-11-29 16:57:57",
+ "updateDateTime": "2021-11-29 16:57:57",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "B49DA01e-CB59-3CB4-963E-b83a1024D5fF",
+ "name": "The development of a phage food additive with the aim to control Salmonella in swine and poultry",
+ "description": "Salmonella spp. is a leading cause of gastrointestinal enteritis in humans where it is largely contracted via contaminated poultry and pork. Phages can be used to control Salmonella infection in the animals, which could break the cycle of infection before the products are accessible for consumption. Here, the potential of twenty-one myoviruses and a siphovirus to eliminate Salmonella in vitro and in vivo is being examined with the aim of developing a biocontrol strategy to curtail the infection ",
+ "externalUrl": "https://le.ac.uk/research/luminaries/professor-martha-clokie",
+ "createDateTime": "2021-11-29 16:57:57",
+ "updateDateTime": "2021-11-29 16:57:57",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "C8D2A9Ed-c7a6-2deB-dB3C-bcaF3f6D5184",
+ "name": "CHiASM Carbon Dioxide (CO2) Database",
+ "description": "Comprehensive hemodynamic assessment of CrCP and RAP during hyperventilation-induced hypocapnia in two distinct age groups (young ≤ 49 and old > 50). CBFV in the middle cerebral artery (CBFV, transcranial Doppler), blood pressure (BP, Finometer) and end-tidal CO2 (EtCO2, capnography) were recorded in 104 healthy individuals (43 young [age 33.8 (9.3) years], 61 old [age 64.1 (8.5) years]) during a minimum of 60 s of metronome-driven hyperventilation-induced hypocapnia. \r\n",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-24 11:55:03",
+ "updateDateTime": "2021-11-24 11:55:03",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "01fca3Ce-6Cef-ce06-b9a5-F589cf04AbD1",
+ "name": "Neurovascular coupling in healthy controls and dementia",
+ "description": "This dataset contains physiological data on heart rate, blood pressure, CO2, and bilateral resting and task-activated cerebral blood flow velocity (CBFv) on healthy controls (HC) and people with Alzheimer's disease (34) and mild cognitive impairment (MCI, n=22). The data contains information on CBFv responses to 20 tasks from the Addenbrooke's cognitive examination (ACE-III) in 50 HC, 10 AD, and 10 MCI, and 5 tasks from the ACE-III in 20 HC, 34 AD, and 22 MCI. ",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-24 11:46:15",
+ "updateDateTime": "2021-11-24 11:46:15",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "FbD32B1c-598A-4Ebe-Aa0b-142B60D8ECbc",
+ "name": "CHiASM database",
+ "description": "Continuous recordings of cerebrovascular and systemic parameters, typically with 5 min duration of cerebral blood flow velocity, arterial blood pressure, ECG, and end-tidal CO2. ",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-24 11:40:15",
+ "updateDateTime": "2021-11-24 11:40:15",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "COVID HEART",
+ "description": "COVID HEART",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "C-MORE",
+ "description": "C-MORE",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "Interfield Strength",
+ "description": "Interfield Strength",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "LENTEN",
+ "description": "LENTEN",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "GO-DCM",
+ "description": "GO-DCM",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "DHF",
+ "description": "DHF",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "CMR Guide",
+ "description": "CMR Guide",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "CTO",
+ "description": "CTO",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "Pre-Op Energy",
+ "description": "Pre-Op Energy",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "Val Card",
+ "description": "Val Card",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "ReST – Aorta",
+ "description": "ReST – Aorta",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "MRI in Aortic dissection",
+ "description": "MRI in Aortic dissection",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "SCAD",
+ "description": "SCAD",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "LiMb",
+ "description": "LiMb",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "DISCORDANCE",
+ "description": "DISCORDANCE",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "CMR in ACS",
+ "description": "CMR in ACS",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "RapidNSTEMI",
+ "description": "RapidNSTEMI",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "ACS (Pilot)",
+ "description": "ACS (Pilot)",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "ECSERT",
+ "description": "ECSERT",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "MIDNIGHT",
+ "description": "MIDNIGHT",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "C-PACE",
+ "description": "C-PACE",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "CYCLE-HD",
+ "description": "CYCLE-HD",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "PATHWAY RCT",
+ "description": "PATHWAY RCT",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "Diamond",
+ "description": "Diamond",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "CMR vs CT-FFR",
+ "description": "CMR vs CT-FFR",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "CE-MARC 2",
+ "description": "CE-MARC 2",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "MR INFORM RCT",
+ "description": "MR INFORM RCT",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "INFUSE AMI",
+ "description": "INFUSE AMI",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "DREAM",
+ "description": "DREAM",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "CATCH-AMI",
+ "description": "CATCH-AMI",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "T-TIME",
+ "description": "T-TIME",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "MVO",
+ "description": "MVO",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "CULPRIT",
+ "description": "CULPRIT",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "FARADAY",
+ "description": "FARADAY",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "BHF STEMI LV remodelling",
+ "description": "BHF STEMI LV remodelling",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "DETA",
+ "description": "DETA",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "ROWING AWAY- IGT",
+ "description": "ROWING AWAY- IGT",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "LYDIA",
+ "description": "LYDIA",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "CardioMET",
+ "description": "CardioMET",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "Predict",
+ "description": "Predict",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "Diastolic",
+ "description": "Diastolic",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "Expedition",
+ "description": "Expedition",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "ELASTIC AS",
+ "description": "ELASTIC AS",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "Ranolazine in AS",
+ "description": "Ranolazine in AS",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "TAVI",
+ "description": "TAVI",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "PRIMID",
+ "description": "PRIMID",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "EVOLVED",
+ "description": "EVOLVED",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "AF28d4E6-9dcC-1c7F-D204-Fe17dCcD39AB",
+ "name": "ELASTIC",
+ "description": "ELASTIC",
+ "externalUrl": "https://le.ac.uk/cardiovascular-sciences",
+ "createDateTime": "2021-11-12 11:01:49",
+ "updateDateTime": "2021-11-12 11:01:49",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "5F0BcdD9-5fe1-f0BD-edCD-FECDb10e76cf",
+ "name": "MUrMuR ",
+ "description": "Measuring and Understanding Multimorbidity Using Routine Data in the UK",
+ "externalUrl": "",
+ "createDateTime": "2022-03-03 16:09:50",
+ "updateDateTime": "2022-03-03 16:09:50",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "D309e4bE-7CF6-a0f2-48E7-96aE5d20F17e",
+ "name": "REQUITE prostate cancer cohort",
+ "description": ".",
+ "externalUrl": "",
+ "createDateTime": "2021-10-13 18:39:48",
+ "updateDateTime": "2021-10-13 18:39:48",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "REQUITE consortium"
+ },
+ {
+ "id": "D309e4bE-7CF6-a0f2-48E7-96aE5d20F17e",
+ "name": "REQUITE lung cancer cohort",
+ "description": ".",
+ "externalUrl": "",
+ "createDateTime": "2021-10-13 18:39:48",
+ "updateDateTime": "2021-10-13 18:39:48",
+ "resourceTypes": "KnowledgeBase",
+ "organisation": "REQUITE consortium"
+ },
+ {
+ "id": "D309e4bE-7CF6-a0f2-48E7-96aE5d20F17e",
+ "name": "REQUITE breast cohort",
+ "description": "maybe later",
+ "externalUrl": "https://requite.eu",
+ "createDateTime": "2021-10-13 18:39:48",
+ "updateDateTime": "2021-10-13 18:39:48",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "REQUITE"
+ },
+ {
+ "id": "2Bf0e47A-0aCA-FE6d-ABbF-e8B1fC2497D5",
+ "name": "LCC-CKD",
+ "description": "Leicestershire primary care chronic kidney disease dataset",
+ "externalUrl": "https://academic.oup.com/ndt/advance-article-abstract/doi/10.1093/ndt/gfaa291/6095733?redirectedFrom=PDF",
+ "createDateTime": "2021-10-07 12:45:19",
+ "updateDateTime": "2021-10-07 12:45:19",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "ADaeC0EB-A43f-C60F-84Ff-82b1509CfcBa",
+ "name": "PSP-CKD data",
+ "description": "CKD data derived from trial of primary care intervention for CKD in Northants. \r\n46 practices data",
+ "externalUrl": "https://jasn.asnjournals.org/content/jnephrol/early/2019/05/15/ASN.2018101042.full.pdf?with-ds=yes%3Fversioned%3Dtrue",
+ "createDateTime": "2021-10-07 12:35:58",
+ "updateDateTime": "2021-10-07 12:35:58",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "University of Leicester"
+ },
+ {
+ "id": "d5102DE9-B456-4fde-AC8f-aFc73eB24bC8",
+ "name": "Paediatric Observation Priority Score (POPS) ",
+ "description": "Outcomes (disposition, diagnosis, length of stay) of children (under 16 years) presenting to the Children's Emergency Department at the Leicester Royal Infirmary from 2018 linked to initial POPS score (obtained at triage). \r\n\r\nData has been used to demonstrate change in acuity levels during COVID (Winning Elizabeth Molyneux Prize at 2020 Royal College of Emergency Medicine Conference) and in BBC media reports during the summer of 2021 ",
+ "externalUrl": "https://www2.le.ac.uk/departments/cardiovascular-sciences/research/intervention/emergency-medicine-group/research/pemla/pops",
+ "createDateTime": "2021-08-31 15:38:17",
+ "updateDateTime": "2021-08-31 15:38:17",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "University Hospitals of Leicester NHS Trust"
+ },
+ {
+ "id": "E765c9CB-0E4d-ae85-bE5C-B6ab2DcFA0C3",
+ "name": "TARN PROMS Prediction Dataset",
+ "description": "Dataset used in the Trauma Audit and Research Network (TARN) project using predictive modelling of major trauma Patient Reported Outcome Measures (PROMS).",
+ "externalUrl": "https://www.tarn.ac.uk/Content.aspx?ca=9&c=3810",
+ "createDateTime": "2021-08-26 09:23:50",
+ "updateDateTime": "2021-08-26 09:23:50",
+ "resourceTypes": "PatientRegistryDataset",
+ "organisation": "Trauma Audit and Research Network"
+ },
+ {
+ "id": "F4CfdA3E-F1Dc-bc8d-EA82-ecC25DB41a89",
+ "name": "FAST: Female Aneurysm screening Study",
+ "description": "An abdominal aortic aneurysm (AAA) is a swelling of the main blood vessel (aorta) in the abdomen. If the swelling gets too large the aorta can burst and this is usually fatal. In order to prevent rupture, AAA can be surgically repaired. This is usually carried out when the size of the AAA is more than 5.5cm in diameter as below this size, the risk of rupture is lower than the risk of surgery. AAA are usually asymptomatic before rupture but can easily and safely be diagnosed by ultrasound scannin",
+ "externalUrl": "https://example.com",
+ "createDateTime": "2022-05-09 13:47:00",
+ "updateDateTime": "2022-05-09 13:47:00",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "NIHR Leicester Biomedical Research Centre"
+ },
+ {
+ "id": "c70aDbAE-0b61-b8fE-8324-43b57fEAadD9",
+ "name": "UKAGS metadata",
+ "description": "UKAGS is a prospective observational cohort study, which between 2011 and 2019 recruited men attending abdominal aortic aneurysm (AAA) screening in England, Wales and Scotland. AAA cases and controls were recruited. Annually, samples of blood and urine were collected for genomic and biomarker analysis, and self-completion postal questionnaires were collected for clinical and SF-8 QoL information. Aortic ultrasound scan measurements, including follow-up, are collected via the national programmes.",
+ "externalUrl": "https://le.ac.uk/ukags/researchers",
+ "createDateTime": "2021-05-05 13:23:47",
+ "updateDateTime": "2021-05-05 13:23:47",
+ "resourceTypes": "BiobankDataset",
+ "organisation": "University of Leicester "
+ }
+
+ ]
diff --git a/deploy/data/individuals.json b/deploy/data/individuals.json
new file mode 100644
index 0000000..a86dd01
--- /dev/null
+++ b/deploy/data/individuals.json
@@ -0,0 +1,651 @@
+[{
+ "_id": {
+ "$oid": "63909d0995d755191c527201"
+ },
+ "subject_id": "S0001",
+ "obo:NCIT_C28421": "obo:NCIT_C16576",
+ "sio:SIO_001003": "ordo:Orphanet_558",
+ "sio:SIO_010056": "obo:HP_0001251",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 14,
+ "efo:EFO_0004847": 13,
+ "obo:NCIT_C156420": 12,
+ "Materials": "Whole Genome Sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527202"
+ },
+ "subject_id": "S0002",
+ "obo:NCIT_C28421": "obo:NCIT_C20197",
+ "sio:SIO_001003": "ordo:Orphanet_34587",
+ "sio:SIO_010056": "obo:HP_0001252",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 15,
+ "efo:EFO_0004847": 14,
+ "obo:NCIT_C156420": 13,
+ "Materials": "Whole Exome Sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527203"
+ },
+ "subject_id": "S0003",
+ "obo:NCIT_C28421": "obo:NCIT_C124294",
+ "sio:SIO_001003": "ordo:Orphanet_1653",
+ "sio:SIO_010056": "obo:HP_0001253",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 16,
+ "efo:EFO_0004847": 15,
+ "obo:NCIT_C156420": 14,
+ "Materials": "Exome panel sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527204"
+ },
+ "subject_id": "S0004",
+ "obo:NCIT_C28421": "obo:NCIT_C17998",
+ "sio:SIO_001003": "ordo:Orphanet_846",
+ "sio:SIO_010056": "obo:HP_0001254",
+ "obo:NCIT_C16612": "HBA2",
+ "obo:NCIT_C25150": 17,
+ "efo:EFO_0004847": 16,
+ "obo:NCIT_C156420": 15,
+ "Materials": "RNA sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527205"
+ },
+ "subject_id": "S0005",
+ "obo:NCIT_C28421": "obo:NCIT_C16576",
+ "sio:SIO_001003": "ordo:Orphanet_558",
+ "sio:SIO_010056": "obo:HP_0001251",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 18,
+ "efo:EFO_0004847": 17,
+ "obo:NCIT_C156420": 16,
+ "Materials": "methylomics"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527206"
+ },
+ "subject_id": "S0006",
+ "obo:NCIT_C28421": "obo:NCIT_C20197",
+ "sio:SIO_001003": "ordo:Orphanet_34587",
+ "sio:SIO_010056": "obo:HP_0001252",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 19,
+ "efo:EFO_0004847": 18,
+ "obo:NCIT_C156420": 17,
+ "Materials": "Epigenomics"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527207"
+ },
+ "subject_id": "S0007",
+ "obo:NCIT_C28421": "obo:NCIT_C124294",
+ "sio:SIO_001003": "ordo:Orphanet_1653",
+ "sio:SIO_010056": "obo:HP_0001253",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 20,
+ "efo:EFO_0004847": 19,
+ "obo:NCIT_C156420": 18,
+ "Materials": "Pedigree data"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527208"
+ },
+ "subject_id": "S0008",
+ "obo:NCIT_C28421": "obo:NCIT_C17998",
+ "sio:SIO_001003": "ordo:Orphanet_846",
+ "sio:SIO_010056": "obo:HP_0001254",
+ "obo:NCIT_C16612": "HBA2",
+ "obo:NCIT_C25150": 21,
+ "efo:EFO_0004847": 20,
+ "obo:NCIT_C156420": 19,
+ "Materials": "Clinical data"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527209"
+ },
+ "subject_id": "S0009",
+ "obo:NCIT_C28421": "obo:NCIT_C16576",
+ "sio:SIO_001003": "ordo:Orphanet_558",
+ "sio:SIO_010056": "obo:HP_0001251",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 22,
+ "efo:EFO_0004847": 21,
+ "obo:NCIT_C156420": 20,
+ "Materials": "Biosamples"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c52720a"
+ },
+ "subject_id": "S0010",
+ "obo:NCIT_C28421": "obo:NCIT_C20197",
+ "sio:SIO_001003": "ordo:Orphanet_34587",
+ "sio:SIO_010056": "obo:HP_0001252",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 23,
+ "efo:EFO_0004847": 22,
+ "obo:NCIT_C156420": 21,
+ "Materials": "Whole Genome Sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c52720b"
+ },
+ "subject_id": "S0011",
+ "obo:NCIT_C28421": "obo:NCIT_C16576",
+ "sio:SIO_001003": "ordo:Orphanet_558",
+ "sio:SIO_010056": "obo:HP_0001251",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 14,
+ "efo:EFO_0004847": 13,
+ "obo:NCIT_C156420": 12,
+ "Materials": "Whole Genome Sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c52720c"
+ },
+ "subject_id": "S0012",
+ "obo:NCIT_C28421": "obo:NCIT_C20197",
+ "sio:SIO_001003": "ordo:Orphanet_34587",
+ "sio:SIO_010056": "obo:HP_0001252",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 15,
+ "efo:EFO_0004847": 14,
+ "obo:NCIT_C156420": 13,
+ "Materials": "Whole Exome Sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c52720d"
+ },
+ "subject_id": "S0013",
+ "obo:NCIT_C28421": "obo:NCIT_C124294",
+ "sio:SIO_001003": "ordo:Orphanet_1653",
+ "sio:SIO_010056": "obo:HP_0001253",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 16,
+ "efo:EFO_0004847": 15,
+ "obo:NCIT_C156420": 14,
+ "Materials": "Exome panel sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c52720e"
+ },
+ "subject_id": "S0014",
+ "obo:NCIT_C28421": "obo:NCIT_C17998",
+ "sio:SIO_001003": "ordo:Orphanet_846",
+ "sio:SIO_010056": "obo:HP_0001254",
+ "obo:NCIT_C16612": "HBA2",
+ "obo:NCIT_C25150": 17,
+ "efo:EFO_0004847": 16,
+ "obo:NCIT_C156420": 15,
+ "Materials": "RNA sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c52720f"
+ },
+ "subject_id": "S0015",
+ "obo:NCIT_C28421": "obo:NCIT_C16576",
+ "sio:SIO_001003": "ordo:Orphanet_558",
+ "sio:SIO_010056": "obo:HP_0001251",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 18,
+ "efo:EFO_0004847": 17,
+ "obo:NCIT_C156420": 16,
+ "Materials": "methylomics"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527210"
+ },
+ "subject_id": "S0016",
+ "obo:NCIT_C28421": "obo:NCIT_C20197",
+ "sio:SIO_001003": "ordo:Orphanet_34587",
+ "sio:SIO_010056": "obo:HP_0001252",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 19,
+ "efo:EFO_0004847": 18,
+ "obo:NCIT_C156420": 17,
+ "Materials": "Epigenomics"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527211"
+ },
+ "subject_id": "S0017",
+ "obo:NCIT_C28421": "obo:NCIT_C124294",
+ "sio:SIO_001003": "ordo:Orphanet_1653",
+ "sio:SIO_010056": "obo:HP_0001253",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 20,
+ "efo:EFO_0004847": 19,
+ "obo:NCIT_C156420": 18,
+ "Materials": "Pedigree data"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527212"
+ },
+ "subject_id": "S0018",
+ "obo:NCIT_C28421": "obo:NCIT_C17998",
+ "sio:SIO_001003": "ordo:Orphanet_846",
+ "sio:SIO_010056": "obo:HP_0001254",
+ "obo:NCIT_C16612": "HBA2",
+ "obo:NCIT_C25150": 21,
+ "efo:EFO_0004847": 20,
+ "obo:NCIT_C156420": 19,
+ "Materials": "Clinical data"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527213"
+ },
+ "subject_id": "S0019",
+ "obo:NCIT_C28421": "obo:NCIT_C16576",
+ "sio:SIO_001003": "ordo:Orphanet_558",
+ "sio:SIO_010056": "obo:HP_0001251",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 22,
+ "efo:EFO_0004847": 21,
+ "obo:NCIT_C156420": 20,
+ "Materials": "Biosamples"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527214"
+ },
+ "subject_id": "S0020",
+ "obo:NCIT_C28421": "obo:NCIT_C20197",
+ "sio:SIO_001003": "ordo:Orphanet_34587",
+ "sio:SIO_010056": "obo:HP_0001252",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 23,
+ "efo:EFO_0004847": 22,
+ "obo:NCIT_C156420": 21,
+ "Materials": "Whole Genome Sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527215"
+ },
+ "subject_id": "S0021",
+ "obo:NCIT_C28421": "obo:NCIT_C16576",
+ "sio:SIO_001003": "ordo:Orphanet_558",
+ "sio:SIO_010056": "obo:HP_0001251",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 14,
+ "efo:EFO_0004847": 13,
+ "obo:NCIT_C156420": 12,
+ "Materials": "Whole Genome Sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527216"
+ },
+ "subject_id": "S0022",
+ "obo:NCIT_C28421": "obo:NCIT_C20197",
+ "sio:SIO_001003": "ordo:Orphanet_34587",
+ "sio:SIO_010056": "obo:HP_0001252",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 15,
+ "efo:EFO_0004847": 14,
+ "obo:NCIT_C156420": 13,
+ "Materials": "Whole Exome Sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527217"
+ },
+ "subject_id": "S0023",
+ "obo:NCIT_C28421": "obo:NCIT_C124294",
+ "sio:SIO_001003": "ordo:Orphanet_1653",
+ "sio:SIO_010056": "obo:HP_0001253",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 16,
+ "efo:EFO_0004847": 15,
+ "obo:NCIT_C156420": 14,
+ "Materials": "Exome panel sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527218"
+ },
+ "subject_id": "S0024",
+ "obo:NCIT_C28421": "obo:NCIT_C17998",
+ "sio:SIO_001003": "ordo:Orphanet_846",
+ "sio:SIO_010056": "obo:HP_0001254",
+ "obo:NCIT_C16612": "HBA2",
+ "obo:NCIT_C25150": 17,
+ "efo:EFO_0004847": 16,
+ "obo:NCIT_C156420": 15,
+ "Materials": "RNA sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527219"
+ },
+ "subject_id": "S0025",
+ "obo:NCIT_C28421": "obo:NCIT_C16576",
+ "sio:SIO_001003": "ordo:Orphanet_558",
+ "sio:SIO_010056": "obo:HP_0001251",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 18,
+ "efo:EFO_0004847": 17,
+ "obo:NCIT_C156420": 16,
+ "Materials": "methylomics"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c52721a"
+ },
+ "subject_id": "S0026",
+ "obo:NCIT_C28421": "obo:NCIT_C20197",
+ "sio:SIO_001003": "ordo:Orphanet_34587",
+ "sio:SIO_010056": "obo:HP_0001252",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 19,
+ "efo:EFO_0004847": 18,
+ "obo:NCIT_C156420": 17,
+ "Materials": "Epigenomics"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c52721b"
+ },
+ "subject_id": "S0027",
+ "obo:NCIT_C28421": "obo:NCIT_C124294",
+ "sio:SIO_001003": "ordo:Orphanet_1653",
+ "sio:SIO_010056": "obo:HP_0001253",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 20,
+ "efo:EFO_0004847": 19,
+ "obo:NCIT_C156420": 18,
+ "Materials": "Pedigree data"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c52721c"
+ },
+ "subject_id": "S0028",
+ "obo:NCIT_C28421": "obo:NCIT_C17998",
+ "sio:SIO_001003": "ordo:Orphanet_846",
+ "sio:SIO_010056": "obo:HP_0001254",
+ "obo:NCIT_C16612": "HBA2",
+ "obo:NCIT_C25150": 21,
+ "efo:EFO_0004847": 20,
+ "obo:NCIT_C156420": 19,
+ "Materials": "Clinical data"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c52721d"
+ },
+ "subject_id": "S0029",
+ "obo:NCIT_C28421": "obo:NCIT_C16576",
+ "sio:SIO_001003": "ordo:Orphanet_558",
+ "sio:SIO_010056": "obo:HP_0001251",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 22,
+ "efo:EFO_0004847": 21,
+ "obo:NCIT_C156420": 20,
+ "Materials": "Biosamples"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c52721e"
+ },
+ "subject_id": "S0030",
+ "obo:NCIT_C28421": "obo:NCIT_C20197",
+ "sio:SIO_001003": "ordo:Orphanet_34587",
+ "sio:SIO_010056": "obo:HP_0001252",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 23,
+ "efo:EFO_0004847": 22,
+ "obo:NCIT_C156420": 21,
+ "Materials": "Whole Genome Sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c52721f"
+ },
+ "subject_id": "S0031",
+ "obo:NCIT_C28421": "obo:NCIT_C16576",
+ "sio:SIO_001003": "ordo:Orphanet_558",
+ "sio:SIO_010056": "obo:HP_0001251",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 14,
+ "efo:EFO_0004847": 13,
+ "obo:NCIT_C156420": 12,
+ "Materials": "Whole Genome Sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527220"
+ },
+ "subject_id": "S0032",
+ "obo:NCIT_C28421": "obo:NCIT_C20197",
+ "sio:SIO_001003": "ordo:Orphanet_34587",
+ "sio:SIO_010056": "obo:HP_0001252",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 15,
+ "efo:EFO_0004847": 14,
+ "obo:NCIT_C156420": 13,
+ "Materials": "Whole Exome Sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527221"
+ },
+ "subject_id": "S0033",
+ "obo:NCIT_C28421": "obo:NCIT_C124294",
+ "sio:SIO_001003": "ordo:Orphanet_1653",
+ "sio:SIO_010056": "obo:HP_0001253",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 16,
+ "efo:EFO_0004847": 15,
+ "obo:NCIT_C156420": 14,
+ "Materials": "Exome panel sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527222"
+ },
+ "subject_id": "S0034",
+ "obo:NCIT_C28421": "obo:NCIT_C17998",
+ "sio:SIO_001003": "ordo:Orphanet_846",
+ "sio:SIO_010056": "obo:HP_0001254",
+ "obo:NCIT_C16612": "HBA2",
+ "obo:NCIT_C25150": 17,
+ "efo:EFO_0004847": 16,
+ "obo:NCIT_C156420": 15,
+ "Materials": "RNA sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527223"
+ },
+ "subject_id": "S0035",
+ "obo:NCIT_C28421": "obo:NCIT_C16576",
+ "sio:SIO_001003": "ordo:Orphanet_558",
+ "sio:SIO_010056": "obo:HP_0001251",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 18,
+ "efo:EFO_0004847": 17,
+ "obo:NCIT_C156420": 16,
+ "Materials": "methylomics"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527224"
+ },
+ "subject_id": "S0036",
+ "obo:NCIT_C28421": "obo:NCIT_C20197",
+ "sio:SIO_001003": "ordo:Orphanet_34587",
+ "sio:SIO_010056": "obo:HP_0001252",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 19,
+ "efo:EFO_0004847": 18,
+ "obo:NCIT_C156420": 17,
+ "Materials": "Epigenomics"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527225"
+ },
+ "subject_id": "S0037",
+ "obo:NCIT_C28421": "obo:NCIT_C124294",
+ "sio:SIO_001003": "ordo:Orphanet_1653",
+ "sio:SIO_010056": "obo:HP_0001253",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 20,
+ "efo:EFO_0004847": 19,
+ "obo:NCIT_C156420": 18,
+ "Materials": "Pedigree data"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527226"
+ },
+ "subject_id": "S0038",
+ "obo:NCIT_C28421": "obo:NCIT_C17998",
+ "sio:SIO_001003": "ordo:Orphanet_846",
+ "sio:SIO_010056": "obo:HP_0001254",
+ "obo:NCIT_C16612": "HBA2",
+ "obo:NCIT_C25150": 21,
+ "efo:EFO_0004847": 20,
+ "obo:NCIT_C156420": 19,
+ "Materials": "Clinical data"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527227"
+ },
+ "subject_id": "S0039",
+ "obo:NCIT_C28421": "obo:NCIT_C16576",
+ "sio:SIO_001003": "ordo:Orphanet_558",
+ "sio:SIO_010056": "obo:HP_0001251",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 22,
+ "efo:EFO_0004847": 21,
+ "obo:NCIT_C156420": 20,
+ "Materials": "Biosamples"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527228"
+ },
+ "subject_id": "S0040",
+ "obo:NCIT_C28421": "obo:NCIT_C20197",
+ "sio:SIO_001003": "ordo:Orphanet_34587",
+ "sio:SIO_010056": "obo:HP_0001252",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 23,
+ "efo:EFO_0004847": 22,
+ "obo:NCIT_C156420": 21,
+ "Materials": "Whole Genome Sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527229"
+ },
+ "subject_id": "S0041",
+ "obo:NCIT_C28421": "obo:NCIT_C16576",
+ "sio:SIO_001003": "ordo:Orphanet_558",
+ "sio:SIO_010056": "obo:HP_0001251",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 14,
+ "efo:EFO_0004847": 13,
+ "obo:NCIT_C156420": 12,
+ "Materials": "Whole Genome Sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c52722a"
+ },
+ "subject_id": "S0042",
+ "obo:NCIT_C28421": "obo:NCIT_C20197",
+ "sio:SIO_001003": "ordo:Orphanet_34587",
+ "sio:SIO_010056": "obo:HP_0001252",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 15,
+ "efo:EFO_0004847": 14,
+ "obo:NCIT_C156420": 13,
+ "Materials": "Whole Exome Sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c52722b"
+ },
+ "subject_id": "S0043",
+ "obo:NCIT_C28421": "obo:NCIT_C124294",
+ "sio:SIO_001003": "ordo:Orphanet_1653",
+ "sio:SIO_010056": "obo:HP_0001253",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 16,
+ "efo:EFO_0004847": 15,
+ "obo:NCIT_C156420": 14,
+ "Materials": "Exome panel sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c52722c"
+ },
+ "subject_id": "S0044",
+ "obo:NCIT_C28421": "obo:NCIT_C17998",
+ "sio:SIO_001003": "ordo:Orphanet_846",
+ "sio:SIO_010056": "obo:HP_0001254",
+ "obo:NCIT_C16612": "HBA2",
+ "obo:NCIT_C25150": 17,
+ "efo:EFO_0004847": 16,
+ "obo:NCIT_C156420": 15,
+ "Materials": "RNA sequence"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c52722d"
+ },
+ "subject_id": "S0045",
+ "obo:NCIT_C28421": "obo:NCIT_C16576",
+ "sio:SIO_001003": "ordo:Orphanet_558",
+ "sio:SIO_010056": "obo:HP_0001251",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 18,
+ "efo:EFO_0004847": 17,
+ "obo:NCIT_C156420": 16,
+ "Materials": "methylomics"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c52722e"
+ },
+ "subject_id": "S0046",
+ "obo:NCIT_C28421": "obo:NCIT_C20197",
+ "sio:SIO_001003": "ordo:Orphanet_34587",
+ "sio:SIO_010056": "obo:HP_0001252",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 19,
+ "efo:EFO_0004847": 18,
+ "obo:NCIT_C156420": 17,
+ "Materials": "Epigenomics"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c52722f"
+ },
+ "subject_id": "S0047",
+ "obo:NCIT_C28421": "obo:NCIT_C124294",
+ "sio:SIO_001003": "ordo:Orphanet_1653",
+ "sio:SIO_010056": "obo:HP_0001253",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 20,
+ "efo:EFO_0004847": 19,
+ "obo:NCIT_C156420": 18,
+ "Materials": "Pedigree data"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527230"
+ },
+ "subject_id": "S0048",
+ "obo:NCIT_C28421": "obo:NCIT_C17998",
+ "sio:SIO_001003": "ordo:Orphanet_846",
+ "sio:SIO_010056": "obo:HP_0001254",
+ "obo:NCIT_C16612": "HBA2",
+ "obo:NCIT_C25150": 21,
+ "efo:EFO_0004847": 20,
+ "obo:NCIT_C156420": 19,
+ "Materials": "Clinical data"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527231"
+ },
+ "subject_id": "S0049",
+ "obo:NCIT_C28421": "obo:NCIT_C16576",
+ "sio:SIO_001003": "ordo:Orphanet_558",
+ "sio:SIO_010056": "obo:HP_0001251",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 22,
+ "efo:EFO_0004847": 21,
+ "obo:NCIT_C156420": 20,
+ "Materials": "Biosamples"
+},{
+ "_id": {
+ "$oid": "63909d0995d755191c527232"
+ },
+ "subject_id": "S0050",
+ "obo:NCIT_C28421": "obo:NCIT_C20197",
+ "sio:SIO_001003": "ordo:Orphanet_34587",
+ "sio:SIO_010056": "obo:HP_0001252",
+ "obo:NCIT_C16612": "LAMP2",
+ "obo:NCIT_C25150": 23,
+ "efo:EFO_0004847": 22,
+ "obo:NCIT_C156420": 21,
+ "Materials": "Whole Genome Sequence"
+}]
\ No newline at end of file
diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml
new file mode 100644
index 0000000..661452b
--- /dev/null
+++ b/deploy/docker-compose.yml
@@ -0,0 +1,129 @@
+version: '3.1'
+
+networks:
+ beacon-priv:
+ idp-priv:
+ pub:
+
+services:
+
+ ###########################################
+ # MongoDB Database
+ ###########################################
+
+ db:
+ image: mongo:5
+ hostname: mongo
+ container_name: beacon_db
+ ports:
+ - 27017:27017
+ environment:
+ MONGO_INITDB_ROOT_USERNAME: vpbib
+ MONGO_INITDB_ROOT_PASSWORD: vpbib
+ MONGO_INITDB_DATABASE: beacon
+ volumes:
+ - ./mongo-init/:/docker-entrypoint-initdb.d/:ro
+ networks:
+ - beacon-priv
+
+ mongo-express:
+ image: mongo-express
+ restart: always
+ ports:
+ - 8081:8081
+ environment:
+ ME_CONFIG_MONGODB_ADMINUSERNAME: vpbib
+ ME_CONFIG_MONGODB_ADMINPASSWORD: vpbib
+ ME_CONFIG_MONGODB_URL: mongodb://vpbib:vpbib@mongo:27017/
+ networks:
+ - beacon-priv
+
+ ###########################################
+ # Beacon
+ ###########################################
+
+ beacon:
+ build: ..
+ image: ejprd/beacon:2.0
+ hostname: beacon
+ container_name: beacon
+ volumes:
+ - ../beacon:/beacon/beacon # inject the code, so we see the modifications "live"
+ - ../ui/static:/beacon/ui/static
+ - ../ui/templates:/beacon/ui/templates
+ - ./conf.py:/beacon/beacon/conf.py
+ - ./logger.yml:/beacon/beacon/logger.yml
+ - ./ontologies:/beacon/ontologies
+ ports:
+ - "5050:5050"
+ networks:
+ - beacon-priv
+ - pub
+ working_dir: '/beacon'
+ entrypoint: ['python','-m','beacon']
+ # entrypoint: ['/bin/sleep','100000000']
+
+ ###########################################
+ # Dummy Permissions server
+ ###########################################
+
+ permissions:
+ image: egarchive/beacon:2.0
+ hostname: beacon-permissions
+ container_name: beacon-permissions
+ volumes:
+ - ../permissions/:/beacon/permissions/ # inject the code, so we see the modifications "live"
+ - ./logger.yml:/beacon/logger.yml
+ ports:
+ - "5051:5051"
+ # networks:
+ # - beacon-priv
+ # - pub
+ #entrypoint: ['/bin/sleep','100000000']
+ working_dir: '/beacon'
+ entrypoint: ['python','-m', 'permissions']
+
+ ###########################################
+ # Local Identity Provider
+ ###########################################
+ # Keycloak is so slow to boot that the DB goes faster
+ # and we don't need a delay in-between. We can rely on the depends_on only.
+
+ idp:
+ image: jboss/keycloak
+ hostname: idp
+ container_name: idp
+ environment:
+ # - KEYCLOAK_FRONTEND_URL=http://idp:8080/auth
+ # - KEYCLOAK_LOGLEVEL=DEBUG
+ # - ROOT_LOGLEVEL=DEBUG
+ - KEYCLOAK_USER=admin
+ - KEYCLOAK_PASSWORD=secret
+ - DB_USER=admin
+ - DB_PASSWORD=secret
+ - DB_VENDOR=postgres
+ - DB_ADDR=idp-db
+ - DB_PORT=5432
+ - DB_DATABASE=keycloak
+ #- DB_SCHEMA=public
+ - KEYCLOAK_IMPORT=/tmp/beacon-realm.json -Dkeycloak.profile.feature.upload_scripts=enabled
+ volumes:
+ - ./beacon-realm.json:/tmp/beacon-realm.json
+ ports:
+ - "8080:8080"
+ # networks:
+ # - pub
+ # - idp-priv
+ depends_on:
+ - idp-db
+
+ idp-db:
+ image: postgres
+ hostname: idp-db
+ container_name: idp-db
+ environment:
+ - POSTGRES_DB=keycloak
+ - POSTGRES_USER=admin
+ - POSTGRES_PASSWORD=secret
+ # networks:
+ # - idp-priv
\ No newline at end of file
diff --git a/deploy/entrypoint.sh b/deploy/entrypoint.sh
new file mode 100644
index 0000000..b541031
--- /dev/null
+++ b/deploy/entrypoint.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+set -e
+
+supervisord -c /beacon/supervisord.conf
+
+exec nginx -c /beacon/nginx.conf -g "daemon off;"
\ No newline at end of file
diff --git a/deploy/extract_filtering_terms.py b/deploy/extract_filtering_terms.py
new file mode 100644
index 0000000..6a49ae4
--- /dev/null
+++ b/deploy/extract_filtering_terms.py
@@ -0,0 +1,210 @@
+import os.path
+import urllib.request
+from typing import List, Dict, Optional
+import re
+from urllib.error import HTTPError
+
+import owlready2
+from pymongo.mongo_client import MongoClient
+import progressbar
+from bson.objectid import ObjectId
+from owlready2 import OwlReadyOntologyParsingError
+from tqdm import tqdm
+from beacon import conf
+
+from beacon.request.ontologies import ONTOLOGY_REGEX
+
+client = MongoClient(
+ "mongodb://{}:{}@{}:{}/{}?authSource={}".format(
+ conf.database_user,
+ conf.database_password,
+ conf.database_host,
+ conf.database_port,
+ conf.database_name,
+ conf.database_auth_source,
+ )
+)
+
+class MyProgressBar:
+ def __init__(self):
+ self.pbar = None
+
+ def __call__(self, block_num: int, block_size: int, total_size: int):
+ if not self.pbar:
+ self.pbar = progressbar.ProgressBar(maxval=total_size)
+ self.pbar.start()
+
+ downloaded = block_num * block_size
+ if downloaded < total_size:
+ self.pbar.update(downloaded)
+ else:
+ self.pbar.finish()
+
+
+def insert_all_ontology_terms_used():
+ collections = client.beacon.list_collection_names()
+ if 'filtering_terms' in collections:
+ collections.remove('filtering_terms')
+ print("Collections:", collections)
+ for c_name in collections:
+ terms = find_ontology_terms_used(c_name)
+ if len(terms) > 0:
+ client.beacon.filtering_terms.insert_many(terms)
+
+
+def get_ontology_name(ontology: owlready2.Ontology) -> str:
+ return ontology.name
+
+
+def load_ontology_obo(ontology_id: str) -> Optional[owlready2.Ontology]:
+ if ontology_id.isalpha():
+ url = "https://www.ebi.ac.uk/{}/{}.obo".format(ontology_id.lower(), ontology_id.lower())
+ path = "ontologies/{}.obo".format(ontology_id)
+ try:
+ if not os.path.exists(path):
+ urllib.request.urlretrieve(url, path, MyProgressBar())
+ return owlready2.get_ontology(path).load()
+ except HTTPError:
+ # TODO: Handle error
+ print("ERROR", HTTPError)
+ pass
+ except OwlReadyOntologyParsingError:
+ # TODO: Handle error
+ pass
+
+def load_ontology(ontology_id: str) -> Optional[owlready2.Ontology]:
+ if ontology_id.isalpha():
+ url = "https://www.ebi.ac.uk/ols/ontologies/{}/download".format(ontology_id)
+ path = "ontologies/{}.owl".format(ontology_id)
+ try:
+ if not os.path.exists(path):
+ urllib.request.urlretrieve(url, path, MyProgressBar())
+ return owlready2.get_ontology(path).load()
+ except HTTPError:
+ # TODO: Handle error
+ print("ERROR", HTTPError)
+ pass
+ except OwlReadyOntologyParsingError:
+ # TODO: Handle error
+ pass
+
+
+def get_ontology_term_label(ontology: owlready2.Ontology, term: str) -> Optional[str]:
+ ontology_class_name = term.replace(':', '_')
+ res = ontology.search(iri="*{}".format(ontology_class_name))
+ for c in res:
+ if c.name == ontology_class_name:
+ if len(c.label) > 0:
+ return c.label.first()
+ else:
+ return c.name
+ return None
+
+
+def get_ontology_term_count(collection_name: str, term: str) -> int:
+ query = {
+ '$text': {
+ '$search': term
+ }
+ }
+ return client.beacon\
+ .get_collection(collection_name)\
+ .count_documents(query)
+
+
+def find_ontology_terms_used(collection_name: str) -> List[Dict]:
+ terms = []
+ terms_ids = set()
+ ontologies = dict()
+ count = client.beacon.get_collection(collection_name).estimated_document_count()
+ xs = client.beacon.get_collection(collection_name).find()
+ for r in tqdm(xs, total=count):
+ matches = ONTOLOGY_REGEX.findall(str(r))
+ for ontology_id, term_id in matches:
+ term = ':'.join([ontology_id, term_id])
+ print(term, ontology_id)
+ if term not in terms_ids:
+ terms_ids.add(term)
+ if ontology_id not in ontologies:
+ ontologies[ontology_id] = load_ontology(ontology_id)
+ if ontologies[ontology_id] is not None:
+ terms.append({
+ 'type': get_ontology_name(ontologies[ontology_id]),
+ 'id': term,
+ 'label': get_ontology_term_label(ontologies[ontology_id], term),
+ # TODO: Use conf.py -> beaconGranularity to not disclouse counts in the filtering terms
+ 'count': get_ontology_term_count(collection_name, term),
+ 'collection': collection_name,
+ })
+ return terms
+
+
+def get_alphanumeric_term_count(collection_name: str, key: str) -> int:
+ return len(client.beacon\
+ .get_collection(collection_name)\
+ .distinct(key))
+
+
+def get_properties_of_document(document, prefix="") -> List[str]:
+ properties = []
+ if document is None or isinstance(document, str) or isinstance(document, int):
+ return []
+ elif isinstance(document, list):
+ for elem in document:
+ properties += get_properties_of_document(elem, prefix)
+ elif isinstance(document, dict):
+ for key, value in document.items():
+ if isinstance(value, ObjectId):
+ continue
+ elif value is None:
+ properties.append(prefix + '.' + key if prefix else key)
+ elif isinstance(value, int):
+ properties.append(prefix + '.' + key if prefix else key)
+ elif isinstance(value, str):
+ properties.append(prefix + '.' + key if prefix else key)
+ elif isinstance(value, list):
+ properties += get_properties_of_document(value, prefix + '.' + key if prefix else key)
+ elif isinstance(value, dict):
+ properties += get_properties_of_document(value, prefix + '.' + key if prefix else key)
+ else:
+ print('Unknown type:', value, ' (', type(value), ')')
+ exit(0)
+ else:
+ print('Unknown type2:', document, ' (', type(document), ')')
+ exit(0)
+ return properties
+
+
+def find_alphanumeric_terms_used(collection_name: str) -> List[Dict]:
+ terms = []
+ terms_ids = set()
+ count = client.beacon.get_collection(collection_name).estimated_document_count()
+ xs = client.beacon.get_collection(collection_name).find()
+ for r in tqdm(xs, total=count):
+ properties = get_properties_of_document(r)
+ for p in properties:
+ if p not in terms_ids:
+ terms_ids.add(p)
+ terms.append({
+ 'type': 'alphanumeric',
+ 'id': p,
+ 'count': get_alphanumeric_term_count(collection_name, p),
+ 'collection': collection_name,
+ })
+ return terms
+
+
+def insert_all_alphanumeric_terms_used():
+ collections = client.beacon.list_collection_names()
+ if 'filtering_terms' in collections:
+ collections.remove('filtering_terms')
+ print("Collections:", collections)
+ for c_name in collections:
+ terms = find_alphanumeric_terms_used(c_name)
+ print(terms)
+ if len(terms) > 0:
+ client.beacon.filtering_terms.insert_many(terms)
+
+
+insert_all_ontology_terms_used()
+insert_all_alphanumeric_terms_used()
diff --git a/deploy/fetch_ontologies.py b/deploy/fetch_ontologies.py
new file mode 100644
index 0000000..3147789
--- /dev/null
+++ b/deploy/fetch_ontologies.py
@@ -0,0 +1,56 @@
+# Query MongoDB to retrieve all of the ontologies used
+from typing import Set
+import re
+from urllib.error import HTTPError
+from pymongo.mongo_client import MongoClient
+
+import urllib.request
+import os
+from tqdm import tqdm
+from beacon import conf
+from beacon.request.ontologies import ONTOLOGY_REGEX
+
+client = MongoClient(
+ "mongodb://{}:{}@{}:{}/{}?authSource={}".format(
+ conf.database_user,
+ conf.database_password,
+ conf.database_host,
+ conf.database_port,
+ conf.database_name,
+ conf.database_auth_source,
+ )
+)
+
+def find_all_ontologies_used() -> Set[str]:
+ ontologies = set()
+ for c_name in ["analyses", "biosamples", "cohorts", "genomicVariations", "datasets", "individuals", "runs"]:
+ ontologies_aux = find_ontologies_used(c_name)
+ ontologies = ontologies.union(ontologies_aux)
+ return ontologies
+
+
+def find_ontologies_used(collection_name: str) -> Set[str]:
+ terms = set()
+ count = client.beacon.get_collection(collection_name).estimated_document_count()
+ xs = client.beacon.get_collection(collection_name).find()
+ for r in tqdm(xs, total=count):
+ matches = ONTOLOGY_REGEX.findall(str(r))
+ for match0, match1 in matches:
+ terms.add(match0)
+ return terms
+
+
+# Try to download each of the ontologies to the ontologies folder
+list_of_ontologies = find_all_ontologies_used()
+
+if len(list_of_ontologies) > 0 and not os.path.exists("ontologies"):
+ os.mkdir("ontologies")
+
+for ontology in tqdm(list_of_ontologies):
+ if ontology.isalpha():
+ url = "https://www.ebi.ac.uk/ols/ontologies/{}/download".format(ontology)
+ path = "ontologies/{}.owl".format(ontology)
+ try:
+ response = urllib.request.urlretrieve(url, path)
+ except HTTPError:
+ continue
diff --git a/deploy/generate_json.sh b/deploy/generate_json.sh
new file mode 100644
index 0000000..bc89af5
--- /dev/null
+++ b/deploy/generate_json.sh
@@ -0,0 +1,63 @@
+
+MODEL_REPO_URL="https://github.com/MrRobb/beacon-v2-Models.git"
+FRAMEWORK_REPO_URL="https://github.com/MrRobb/beacon-framework-v2.git"
+
+MODEL_REPLACE_URL="https:\/\/raw.githubusercontent.com\/ga4gh-beacon\/beacon-v2-Models\/main\/"
+FRAMEWORK_REPLACE_URL="https:\/\/raw.githubusercontent.com\/ga4gh-beacon\/beacon-framework-v2\/main\/"
+
+MODEL_REPO_LOCATION="beacon-v2-Models"
+FRAMEWORK_REPO_LOCATION="beacon-framework-v2"
+
+DATA_FOLDER="data"
+
+# Clean
+rm -rf ${MODEL_REPO_LOCATION} ${FRAMEWORK_REPO_LOCATION} ${DATA_FOLDER}
+
+# Create data folder
+mkdir ${DATA_FOLDER}
+
+# Download repositories
+git clone ${MODEL_REPO_URL} ${MODEL_REPO_LOCATION}
+git clone ${FRAMEWORK_REPO_URL} ${FRAMEWORK_REPO_LOCATION}
+
+# Remove endpoints.json files
+find ${MODEL_REPO_LOCATION} -type f -name "endpoints.json" -delete
+find ${FRAMEWORK_REPO_LOCATION} -type f -name "endpoints.json" -delete
+
+# Replace references
+case "$(uname -s)" in
+
+ Darwin)
+ echo 'Mac OS X'
+ find ${MODEL_REPO_LOCATION} -type f -name "*.json" -exec sed -i ".bak" "s/${MODEL_REPLACE_URL}/${MODEL_REPO_LOCATION}/g" {} +
+ find ${FRAMEWORK_REPO_LOCATION} -type f -name "*.json" -exec sed -i ".bak" "s/${FRAMEWORK_REPLACE_URL}/${FRAMEWORK_REPO_LOCATION}/g" {} +
+ ;;
+
+ Linux)
+ echo 'Linux'
+ find ${MODEL_REPO_LOCATION} -type f -name "*.json" -exec sed -i "s/${MODEL_REPLACE_URL}/${MODEL_REPO_LOCATION}/g" {} +
+ find ${FRAMEWORK_REPO_LOCATION} -type f -name "*.json" -exec sed -i "s/${FRAMEWORK_REPLACE_URL}/${FRAMEWORK_REPO_LOCATION}/g" {} +
+ ;;
+
+ *)
+ echo 'Other OS: Not supported'
+esac
+
+# Resolve references
+# npm install -g json-dereference-cli
+python3 cleanup_json.py ${MODEL_REPO_LOCATION}
+python3 cleanup_json.py ${FRAMEWORK_REPO_LOCATION}
+
+
+# Generate fake schemas
+# npm install -g json-schema-faker-cli
+for i in $(seq 1 $1)
+do
+ fake-schema "${MODEL_REPO_LOCATION}/BEACON-V2-Model/analyses/defaultSchema.json" > "${DATA_FOLDER}/analyses${i}.json"
+ fake-schema "${MODEL_REPO_LOCATION}/BEACON-V2-Model/biosamples/defaultSchema.json" > "${DATA_FOLDER}/biosamples${i}.json"
+ fake-schema "${MODEL_REPO_LOCATION}/BEACON-V2-Model/cohorts/defaultSchema.json" > "${DATA_FOLDER}/cohorts${i}.json"
+ fake-schema "${MODEL_REPO_LOCATION}/BEACON-V2-Model/datasets/defaultSchema.json" > "${DATA_FOLDER}/datasets${i}.json"
+ fake-schema "${MODEL_REPO_LOCATION}/BEACON-V2-Model/genomicVariations/defaultSchema.json" > "${DATA_FOLDER}/genomicVariations${i}.json"
+ fake-schema "${MODEL_REPO_LOCATION}/BEACON-V2-Model/individuals/defaultSchema.json" > "${DATA_FOLDER}/individuals${i}.json"
+ fake-schema "${MODEL_REPO_LOCATION}/BEACON-V2-Model/runs/defaultSchema.json" > "${DATA_FOLDER}/runs${i}.json"
+done
diff --git a/deploy/load_json.py b/deploy/load_json.py
new file mode 100644
index 0000000..7a6c8ac
--- /dev/null
+++ b/deploy/load_json.py
@@ -0,0 +1,36 @@
+import json
+import argparse
+from pymongo.mongo_client import MongoClient
+
+entities = ["analyses", "biosamples", "cohorts", "datasets", "genomicVariations", "individuals", "runs"]
+
+def main():
+ parser = argparse.ArgumentParser("JSON MongoDB Loader")
+
+ parser.add_argument("--db", dest="db", action="store", help="Database URI", required=True)
+ parser.add_argument("--files", dest="files", action="store", help="JSON Files path", required=True, nargs='+')
+ parser.add_argument("--collection", dest="collection", action="store", help="Collection to store the data", required=True, choices=entities)
+
+ args = parser.parse_args()
+
+ print(args.files, "->", args.db, "[", args.collection, "]")
+
+ all_instances = []
+
+ for file in args.files:
+ with open(file, 'r') as json_file:
+ data = json.load(json_file)
+ if isinstance(data, dict):
+ print("Loading multiple files with one instance each")
+ all_instances.append(data)
+ else:
+ print("Loading only one file with multiple instances")
+ all_instances = data
+ break
+
+ client = MongoClient(args.db)
+ client.beacon.get_collection(args.collection).insert_many(all_instances)
+ print("DONE!")
+
+if __name__ == "__main__":
+ main()
diff --git a/deploy/logger.yml b/deploy/logger.yml
new file mode 100644
index 0000000..fc735f0
--- /dev/null
+++ b/deploy/logger.yml
@@ -0,0 +1,32 @@
+---
+version: 1
+#disable_existing_loggers: True
+root:
+ level: NOTSET
+ handlers: [ noHandler ]
+
+loggers:
+ __main__:
+ level: DEBUG
+ handlers: [ console ]
+ beacon:
+ level: DEBUG
+ handlers: [ console ]
+ propagate: True
+ aiohttp:
+ level: INFO
+ handlers: [ console ]
+
+handlers:
+ noHandler:
+ class: logging.NullHandler
+ level: NOTSET
+ console:
+ class: logging.StreamHandler
+ formatter: simple
+ stream: ext://sys.stderr
+
+formatters:
+ simple:
+ format: "[{name:^10}][{levelname:^6}] (L{lineno}) {message}"
+ style: "{"
diff --git a/deploy/mongo-init/init.js b/deploy/mongo-init/init.js
new file mode 100644
index 0000000..844d856
--- /dev/null
+++ b/deploy/mongo-init/init.js
@@ -0,0 +1,19 @@
+conn = new Mongo({Â useUnifiedTopology: true });
+db = conn.getDB("beacon");
+
+
+// db.beacon.createIndex({ "address.zip": 1 }, { unique: false });
+// db.beacon.insert({ "address": { "city": "Paris", "zip": "123" }, "name": "Mike", "phone": "1234" });
+// db.beacon.insert({ "address": { "city": "Marsel", "zip": "321" }, "name": "Helga", "phone": "4321" });
+
+// Create collections
+
+
+db.createCollection("datasets");
+db.createCollection("individuals");
+
+
+// Create indexes for all the entities in the database
+
+db.datasets.createIndex([('$**', 'text')]);
+db.individuals.createIndex([('$**', 'text')]);
diff --git a/deploy/nginx.conf b/deploy/nginx.conf
new file mode 100644
index 0000000..c40d68c
--- /dev/null
+++ b/deploy/nginx.conf
@@ -0,0 +1,131 @@
+# user beacon;
+worker_processes auto;
+pid /var/run/beacon/nginx.pid;
+include /etc/nginx/modules-enabled/*.conf;
+
+events {
+ worker_connections 768;
+ # multi_accept on;
+}
+
+http {
+
+ ##
+ # Basic Settings
+ ##
+
+ sendfile on;
+ tcp_nopush on;
+ tcp_nodelay on;
+ keepalive_timeout 65;
+ types_hash_max_size 2048;
+ # server_tokens off;
+
+ # server_names_hash_bucket_size 64;
+ # server_name_in_redirect off;
+
+ include /etc/nginx/mime.types;
+ default_type application/octet-stream;
+
+ ##
+ # SSL Settings
+ ##
+
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
+ ssl_prefer_server_ciphers on;
+
+ ##
+ # Logging Settings
+ ##
+
+ access_log /var/log/nginx/access.log;
+ error_log /var/log/nginx/error.log;
+
+ ##
+ # Gzip Settings
+ ##
+
+ gzip on;
+
+ # gzip_vary on;
+ # gzip_proxied any;
+ # gzip_comp_level 6;
+ # gzip_buffers 16 8k;
+ # gzip_http_version 1.1;
+ # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
+
+ ##
+ # Virtual Host Configs
+ ##
+ upstream beacon {
+ # fail_timeout=0 means we always retry an upstream even if it failed
+ # to return a good HTTP response
+
+ # Unix domain servers
+ server unix:/var/run/beacon/instance_1.sock fail_timeout=0;
+ server unix:/var/run/beacon/instance_2.sock fail_timeout=0;
+ server unix:/var/run/beacon/instance_3.sock fail_timeout=0;
+ server unix:/var/run/beacon/instance_4.sock fail_timeout=0;
+
+ # Unix domain sockets are used in this example due to their high performance,
+ # but TCP/IP sockets could be used instead:
+ # server 127.0.0.1:8081 fail_timeout=0;
+ # server 127.0.0.1:8082 fail_timeout=0;
+ # server 127.0.0.1:8083 fail_timeout=0;
+ # server 127.0.0.1:8084 fail_timeout=0;
+ }
+
+ server {
+ listen 8080 default_server;
+ listen [::]:8080 default_server;
+
+ server_name _;
+ client_max_body_size 4G;
+
+ location /static {
+ root /beacon;
+ expires max;
+ add_header Pragma public;
+ add_header Cache-Control "public, must-revalidate, proxy-revalidate";
+ }
+
+
+ location / {
+
+
+ # Adding the wide-open CORS settings
+ if ($request_method = 'OPTIONS') {
+ add_header 'Access-Control-Allow-Origin' '*';
+ add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
+ #
+ # Custom headers and headers various browsers *should* be OK with but aren't
+ #
+ add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
+ # Tell client that this pre-flight info is valid for 20 days
+ add_header 'Access-Control-Max-Age' 1728000;
+ add_header 'Content-Type' 'text/plain; charset=utf-8';
+ add_header 'Content-Length' 0;
+ return 204;
+ }
+ if ($request_method = 'POST') {
+ add_header 'Access-Control-Allow-Origin' '*';
+ add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
+ add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
+ add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
+ }
+ if ($request_method = 'GET') {
+ add_header 'Access-Control-Allow-Origin' '*';
+ add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
+ add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
+ add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
+ }
+
+ # Forward to the upstream
+ proxy_set_header Host $http_host;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_redirect off;
+ proxy_buffering off;
+ proxy_pass http://beacon;
+ }
+ }
+}
\ No newline at end of file
diff --git a/deploy/ontologies/README.md b/deploy/ontologies/README.md
new file mode 100644
index 0000000..c577a40
--- /dev/null
+++ b/deploy/ontologies/README.md
@@ -0,0 +1,13 @@
+# Ontologies
+
+> This step might require a bit of tinkering since some ontologies used in the dummy data will fail to loaded. I recommend skipping this step unless you know what you are doing.
+
+You can automatically fetch the ontologies that the database is using with the following script:
+
+```bash
+# Install the dependencies
+pip3 install pymongo tqdm
+
+# From the deploy/ directory
+python3 fetch_ontologies.py
+```
diff --git a/deploy/reindex.py b/deploy/reindex.py
new file mode 100644
index 0000000..747f2bf
--- /dev/null
+++ b/deploy/reindex.py
@@ -0,0 +1,15 @@
+from pymongo.mongo_client import MongoClient
+import conf
+
+client = MongoClient(
+ "mongodb://{}:{}@{}:{}/{}?authSource={}".format(
+ conf.database_user,
+ conf.database_password,
+ conf.database_host,
+ conf.database_port,
+ conf.database_name,
+ conf.database_auth_source,
+ )
+)
+client.beacon.datasets.create_index([("$**", "text")])
+client.beacon.individuals.create_index([("$**", "text")])
diff --git a/deploy/supervisord.conf b/deploy/supervisord.conf
new file mode 100644
index 0000000..120fe6e
--- /dev/null
+++ b/deploy/supervisord.conf
@@ -0,0 +1,28 @@
+; supervisor config file
+
+; [unix_http_server]
+; file=/var/run/supervisor.sock ; (the path to the socket file)
+; chmod=0700 ; sockef file mode (default 0700)
+
+; ; Manager web interface
+; [inet_http_server]
+; port = 9001
+; username = user ; Basic auth username
+; password = pass ; Basic auth password
+
+[supervisord]
+logfile=/var/log/supervisord/supervisord.log ; (main log file;default $CWD/supervisord.log)
+pidfile=/var/run/beacon/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
+childlogdir=/var/log/supervisord ; ('AUTO' child log dir, default $TEMP)
+
+[program:beacon]
+numprocs = 4
+numprocs_start = 1
+process_name = beacon_%(process_num)s
+
+; Unix socket paths are specified by command line.
+command=python -m beacon /var/run/beacon/instance_%(process_num)s.sock
+
+user=beacon
+autostart=true
+autorestart=true
\ No newline at end of file
diff --git a/frontend/.gitignore b/frontend/.gitignore
new file mode 100644
index 0000000..4d29575
--- /dev/null
+++ b/frontend/.gitignore
@@ -0,0 +1,23 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# production
+/build
+
+# misc
+.DS_Store
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
diff --git a/frontend/README.md b/frontend/README.md
new file mode 100644
index 0000000..c0541f9
--- /dev/null
+++ b/frontend/README.md
@@ -0,0 +1,70 @@
+# Getting Started with Create React App
+
+This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
+
+## Available Scripts
+
+In the project directory, you can run:
+
+### `yarn start`
+
+Runs the app in the development mode.\
+Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
+
+The page will reload when you make changes.\
+You may also see any lint errors in the console.
+
+### `yarn test`
+
+Launches the test runner in the interactive watch mode.\
+See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
+
+### `yarn build`
+
+Builds the app for production to the `build` folder.\
+It correctly bundles React in production mode and optimizes the build for the best performance.
+
+The build is minified and the filenames include the hashes.\
+Your app is ready to be deployed!
+
+See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
+
+### `yarn eject`
+
+**Note: this is a one-way operation. Once you `eject`, you can't go back!**
+
+If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
+
+Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
+
+You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
+
+## Learn More
+
+You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
+
+To learn React, check out the [React documentation](https://reactjs.org/).
+
+### Code Splitting
+
+This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
+
+### Analyzing the Bundle Size
+
+This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
+
+### Making a Progressive Web App
+
+This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
+
+### Advanced Configuration
+
+This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
+
+### Deployment
+
+This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
+
+### `yarn build` fails to minify
+
+This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
diff --git a/frontend/package.json b/frontend/package.json
new file mode 100644
index 0000000..aa87045
--- /dev/null
+++ b/frontend/package.json
@@ -0,0 +1,41 @@
+{
+ "name": "frontend",
+ "version": "0.1.0",
+ "private": true,
+ "dependencies": {
+ "@testing-library/jest-dom": "^5.14.1",
+ "@testing-library/react": "^13.0.0",
+ "@testing-library/user-event": "^13.2.1",
+ "bootstrap": "5.2.2",
+ "bootswatch": "5.2.2",
+ "react": "^18.2.0",
+ "react-bootstrap": "2.6.0",
+ "react-dom": "^18.2.0",
+ "react-scripts": "5.0.1",
+ "web-vitals": "^2.1.0"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject"
+ },
+ "eslintConfig": {
+ "extends": [
+ "react-app",
+ "react-app/jest"
+ ]
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ }
+}
diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico
new file mode 100644
index 0000000..a11777c
Binary files /dev/null and b/frontend/public/favicon.ico differ
diff --git a/frontend/public/index.html b/frontend/public/index.html
new file mode 100644
index 0000000..85ec557
--- /dev/null
+++ b/frontend/public/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+ Rare Diseases
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/public/logo192.png b/frontend/public/logo192.png
new file mode 100644
index 0000000..fc44b0a
Binary files /dev/null and b/frontend/public/logo192.png differ
diff --git a/frontend/public/logo512.png b/frontend/public/logo512.png
new file mode 100644
index 0000000..a4e47a6
Binary files /dev/null and b/frontend/public/logo512.png differ
diff --git a/frontend/public/manifest.json b/frontend/public/manifest.json
new file mode 100644
index 0000000..080d6c7
--- /dev/null
+++ b/frontend/public/manifest.json
@@ -0,0 +1,25 @@
+{
+ "short_name": "React App",
+ "name": "Create React App Sample",
+ "icons": [
+ {
+ "src": "favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ },
+ {
+ "src": "logo192.png",
+ "type": "image/png",
+ "sizes": "192x192"
+ },
+ {
+ "src": "logo512.png",
+ "type": "image/png",
+ "sizes": "512x512"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
diff --git a/frontend/public/robots.txt b/frontend/public/robots.txt
new file mode 100644
index 0000000..e9e57dc
--- /dev/null
+++ b/frontend/public/robots.txt
@@ -0,0 +1,3 @@
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:
diff --git a/frontend/src/App.css b/frontend/src/App.css
new file mode 100644
index 0000000..74b5e05
--- /dev/null
+++ b/frontend/src/App.css
@@ -0,0 +1,38 @@
+.App {
+ text-align: center;
+}
+
+.App-logo {
+ height: 40vmin;
+ pointer-events: none;
+}
+
+@media (prefers-reduced-motion: no-preference) {
+ .App-logo {
+ animation: App-logo-spin infinite 20s linear;
+ }
+}
+
+.App-header {
+ background-color: #282c34;
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ font-size: calc(10px + 2vmin);
+ color: white;
+}
+
+.App-link {
+ color: #61dafb;
+}
+
+@keyframes App-logo-spin {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
diff --git a/frontend/src/App.js b/frontend/src/App.js
new file mode 100644
index 0000000..a4cf12e
--- /dev/null
+++ b/frontend/src/App.js
@@ -0,0 +1,15 @@
+import React from 'react';
+
+import './App.css';
+
+import { Container } from 'react-bootstrap';
+
+function App () {
+ return (
+
+