diff --git a/CHANGELOG.md b/CHANGELOG.md
index 54128c7c41c..a3cb14a7d6f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@ changes in the following format: PR #1234***
#### Core
- Menus are now maintained by modules and no longer in the SQL database (PR #5839)
+- Very old instrument relying on QuickForm may have issues due to code changes (PR #4928)
#### Modules
##### module1
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000000..6dc0959ae65
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,16 @@
+LORIS is primarily developed at [McGill University](https://www.mcgill.ca/) within the [McGill Centre For Integrative Neuroscience](http://mcin.ca/). As such, we are governed by the McGill Faculty of Medicine's [code of conduct](https://www.mcgill.ca/medicine/about/our-vision-mission-values/code-conduct).
+
+The LORIS project also pushes certain philosophies such as:
+
+1) An environment of inclusion
+
+2) A respectful manner of discourse and disagreement
+
+3) A strong commitment to timely resolution of issues
+
+4) An open and free environment to voice opinions and suggestions
+
+5) Having the goal of transparency and clarity
+
+As open source software we encourage contributions from other sources, and as such we need to allow for heterogeneous ideas. When interacting within the LORIS community keep in mind that we are a diverse community incorporating people of many different backgrounds, and it is expected that everyone be treated with respect.
+
diff --git a/README.md b/README.md
index a8e1d232ffa..8ebc467a7a2 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
-[![Build Status](https://travis-ci.org/aces/Loris.svg?branch=master)](https://travis-ci.org/aces/Loris) [![Documentation Status](https://readthedocs.org/projects/acesloris/badge/?version=latest)](https://acesloris.readthedocs.io/en/latest/?badge=latest)
+[![Build Status](https://travis-ci.org/aces/Loris.svg?branch=master)](https://travis-ci.org/aces/Loris)
+[![Minimum PHP Version](https://img.shields.io/travis/php-v/aces/loris/master?color=787CB5)](https://php.net/)
# LORIS Neuroimaging Platform
diff --git a/SQL/0000-00-01-Permission.sql b/SQL/0000-00-01-Permission.sql
index 2d2237e9ebd..1ff30d45e56 100644
--- a/SQL/0000-00-01-Permission.sql
+++ b/SQL/0000-00-01-Permission.sql
@@ -101,7 +101,8 @@ INSERT INTO `permissions` VALUES
(53,'instrument_manager_write', 'Instrument Manager: Install new instruments via file upload', 2),
(54,'publication_view', 'Publication - Access to module', 2),
(55,'publication_propose', 'Publication - Propose a project', 2),
- (56,'publication_approve', 'Publication - Approve or reject proposed publication projects', 2);
+ (56,'publication_approve', 'Publication - Approve or reject proposed publication projects', 2),
+ (57, 'candidate_dob_edit', 'Edit dates of birth', 2);
INSERT INTO `user_perm_rel` (userID, permID)
diff --git a/SQL/New_patches/2019_07_02_Add_Edit_DoB_Permissions.sql b/SQL/New_patches/2019_07_02_Add_Edit_DoB_Permissions.sql
new file mode 100644
index 00000000000..e390be8cab8
--- /dev/null
+++ b/SQL/New_patches/2019_07_02_Add_Edit_DoB_Permissions.sql
@@ -0,0 +1,5 @@
+INSERT INTO permissions (code, description, categoryID) VALUES
+ ("candidate_dob_edit","Edit dates of birth",2);
+
+INSERT INTO user_perm_rel VALUES
+ (1, (SELECT permID FROM permissions WHERE code='candidate_dob_edit'));
diff --git a/composer.json b/composer.json
index 4fdd71a19f3..9f99c6d4786 100644
--- a/composer.json
+++ b/composer.json
@@ -19,7 +19,8 @@
"phpunit/phpunit" : "7.0.0",
"facebook/webdriver" : "dev-master",
"phan/phan": ">=2.3.0",
- "phpmd/phpmd": "~2.8"
+ "phpmd/phpmd": "~2.8",
+ "phpstan/phpstan": "^0.12"
},
"scripts": {
"pre-install-cmd": "mkdir -p project/libraries"
diff --git a/composer.lock b/composer.lock
index fdd81273c42..c68f3fc7ad6 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "5353130ae3bec8488ec5926fc760b499",
+ "content-hash": "35081adf4154e1d4af5a45e6843a3cad",
"packages": [
{
"name": "bjeavons/zxcvbn-php",
@@ -1170,6 +1170,57 @@
"description": "A more advanced JSONRPC implementation",
"time": "2019-09-12T22:41:08+00:00"
},
+ {
+ "name": "jean85/pretty-package-versions",
+ "version": "1.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Jean85/pretty-package-versions.git",
+ "reference": "75c7effcf3f77501d0e0caa75111aff4daa0dd48"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/75c7effcf3f77501d0e0caa75111aff4daa0dd48",
+ "reference": "75c7effcf3f77501d0e0caa75111aff4daa0dd48",
+ "shasum": ""
+ },
+ "require": {
+ "ocramius/package-versions": "^1.2.0",
+ "php": "^7.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^6.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Jean85\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Alessandro Lai",
+ "email": "alessandro.lai85@gmail.com"
+ }
+ ],
+ "description": "A wrapper for ocramius/package-versions to get pretty versions strings",
+ "keywords": [
+ "composer",
+ "package",
+ "release",
+ "versions"
+ ],
+ "time": "2018-06-13T13:22:40+00:00"
+ },
{
"name": "microsoft/tolerant-php-parser",
"version": "v0.0.18",
@@ -1305,6 +1356,636 @@
"description": "Map nested JSON structures onto PHP classes",
"time": "2019-08-15T19:41:25+00:00"
},
+ {
+ "name": "nette/bootstrap",
+ "version": "v3.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nette/bootstrap.git",
+ "reference": "b45a1e33b6a44beb307756522396551e5a9ff249"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nette/bootstrap/zipball/b45a1e33b6a44beb307756522396551e5a9ff249",
+ "reference": "b45a1e33b6a44beb307756522396551e5a9ff249",
+ "shasum": ""
+ },
+ "require": {
+ "nette/di": "^3.0",
+ "nette/utils": "^3.0",
+ "php": ">=7.1"
+ },
+ "conflict": {
+ "tracy/tracy": "<2.6"
+ },
+ "require-dev": {
+ "latte/latte": "^2.2",
+ "nette/application": "^3.0",
+ "nette/caching": "^3.0",
+ "nette/database": "^3.0",
+ "nette/forms": "^3.0",
+ "nette/http": "^3.0",
+ "nette/mail": "^3.0",
+ "nette/robot-loader": "^3.0",
+ "nette/safe-stream": "^2.2",
+ "nette/security": "^3.0",
+ "nette/tester": "^2.0",
+ "tracy/tracy": "^2.6"
+ },
+ "suggest": {
+ "nette/robot-loader": "to use Configurator::createRobotLoader()",
+ "tracy/tracy": "to use Configurator::enableTracy()"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause",
+ "GPL-2.0",
+ "GPL-3.0"
+ ],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "https://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "https://nette.org/contributors"
+ }
+ ],
+ "description": "🅱 Nette Bootstrap: the simple way to configure and bootstrap your Nette application.",
+ "homepage": "https://nette.org",
+ "keywords": [
+ "bootstrapping",
+ "configurator",
+ "nette"
+ ],
+ "time": "2019-09-30T08:19:38+00:00"
+ },
+ {
+ "name": "nette/di",
+ "version": "v3.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nette/di.git",
+ "reference": "4aff517a1c6bb5c36fa09733d4cea089f529de6d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nette/di/zipball/4aff517a1c6bb5c36fa09733d4cea089f529de6d",
+ "reference": "4aff517a1c6bb5c36fa09733d4cea089f529de6d",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "nette/neon": "^3.0",
+ "nette/php-generator": "^3.2.2",
+ "nette/robot-loader": "^3.2",
+ "nette/schema": "^1.0",
+ "nette/utils": "^3.0",
+ "php": ">=7.1"
+ },
+ "conflict": {
+ "nette/bootstrap": "<3.0"
+ },
+ "require-dev": {
+ "nette/tester": "^2.2",
+ "tracy/tracy": "^2.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ],
+ "files": [
+ "src/compatibility.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause",
+ "GPL-2.0",
+ "GPL-3.0"
+ ],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "https://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "https://nette.org/contributors"
+ }
+ ],
+ "description": "💎 Nette Dependency Injection Container: Flexible, compiled and full-featured DIC with perfectly usable autowiring and support for all new PHP 7.1 features.",
+ "homepage": "https://nette.org",
+ "keywords": [
+ "compiled",
+ "di",
+ "dic",
+ "factory",
+ "ioc",
+ "nette",
+ "static"
+ ],
+ "time": "2019-08-07T12:11:33+00:00"
+ },
+ {
+ "name": "nette/finder",
+ "version": "v2.5.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nette/finder.git",
+ "reference": "14164e1ddd69e9c5f627ff82a10874b3f5bba5fe"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nette/finder/zipball/14164e1ddd69e9c5f627ff82a10874b3f5bba5fe",
+ "reference": "14164e1ddd69e9c5f627ff82a10874b3f5bba5fe",
+ "shasum": ""
+ },
+ "require": {
+ "nette/utils": "^2.4 || ~3.0.0",
+ "php": ">=7.1"
+ },
+ "conflict": {
+ "nette/nette": "<2.2"
+ },
+ "require-dev": {
+ "nette/tester": "^2.0",
+ "tracy/tracy": "^2.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.5-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause",
+ "GPL-2.0",
+ "GPL-3.0"
+ ],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "https://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "https://nette.org/contributors"
+ }
+ ],
+ "description": "🔍 Nette Finder: find files and directories with an intuitive API.",
+ "homepage": "https://nette.org",
+ "keywords": [
+ "filesystem",
+ "glob",
+ "iterator",
+ "nette"
+ ],
+ "time": "2019-07-11T18:02:17+00:00"
+ },
+ {
+ "name": "nette/neon",
+ "version": "v3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nette/neon.git",
+ "reference": "cbff32059cbdd8720deccf9e9eace6ee516f02eb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nette/neon/zipball/cbff32059cbdd8720deccf9e9eace6ee516f02eb",
+ "reference": "cbff32059cbdd8720deccf9e9eace6ee516f02eb",
+ "shasum": ""
+ },
+ "require": {
+ "ext-iconv": "*",
+ "ext-json": "*",
+ "php": ">=7.0"
+ },
+ "require-dev": {
+ "nette/tester": "^2.0",
+ "tracy/tracy": "^2.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause",
+ "GPL-2.0",
+ "GPL-3.0"
+ ],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "https://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "https://nette.org/contributors"
+ }
+ ],
+ "description": "? Nette NEON: encodes and decodes NEON file format.",
+ "homepage": "http://ne-on.org",
+ "keywords": [
+ "export",
+ "import",
+ "neon",
+ "nette",
+ "yaml"
+ ],
+ "time": "2019-02-05T21:30:40+00:00"
+ },
+ {
+ "name": "nette/php-generator",
+ "version": "v3.2.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nette/php-generator.git",
+ "reference": "aea6e81437bb238e5f0e5b5ce06337433908e63b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nette/php-generator/zipball/aea6e81437bb238e5f0e5b5ce06337433908e63b",
+ "reference": "aea6e81437bb238e5f0e5b5ce06337433908e63b",
+ "shasum": ""
+ },
+ "require": {
+ "nette/utils": "^2.4.2 || ~3.0.0",
+ "php": ">=7.1"
+ },
+ "require-dev": {
+ "nette/tester": "^2.0",
+ "tracy/tracy": "^2.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.2-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause",
+ "GPL-2.0",
+ "GPL-3.0"
+ ],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "https://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "https://nette.org/contributors"
+ }
+ ],
+ "description": "🐘 Nette PHP Generator: generates neat PHP code for you. Supports new PHP 7.3 features.",
+ "homepage": "https://nette.org",
+ "keywords": [
+ "code",
+ "nette",
+ "php",
+ "scaffolding"
+ ],
+ "time": "2019-07-05T13:01:56+00:00"
+ },
+ {
+ "name": "nette/robot-loader",
+ "version": "v3.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nette/robot-loader.git",
+ "reference": "0712a0e39ae7956d6a94c0ab6ad41aa842544b5c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nette/robot-loader/zipball/0712a0e39ae7956d6a94c0ab6ad41aa842544b5c",
+ "reference": "0712a0e39ae7956d6a94c0ab6ad41aa842544b5c",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "nette/finder": "^2.5",
+ "nette/utils": "^3.0",
+ "php": ">=7.1"
+ },
+ "require-dev": {
+ "nette/tester": "^2.0",
+ "tracy/tracy": "^2.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.2-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause",
+ "GPL-2.0",
+ "GPL-3.0"
+ ],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "https://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "https://nette.org/contributors"
+ }
+ ],
+ "description": "? Nette RobotLoader: high performance and comfortable autoloader that will search and autoload classes within your application.",
+ "homepage": "https://nette.org",
+ "keywords": [
+ "autoload",
+ "class",
+ "interface",
+ "nette",
+ "trait"
+ ],
+ "time": "2019-03-08T21:57:24+00:00"
+ },
+ {
+ "name": "nette/schema",
+ "version": "v1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nette/schema.git",
+ "reference": "6241d8d4da39e825dd6cb5bfbe4242912f4d7e4d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nette/schema/zipball/6241d8d4da39e825dd6cb5bfbe4242912f4d7e4d",
+ "reference": "6241d8d4da39e825dd6cb5bfbe4242912f4d7e4d",
+ "shasum": ""
+ },
+ "require": {
+ "nette/utils": "^3.0.1",
+ "php": ">=7.1"
+ },
+ "require-dev": {
+ "nette/tester": "^2.2",
+ "tracy/tracy": "^2.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause",
+ "GPL-2.0",
+ "GPL-3.0"
+ ],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "https://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "https://nette.org/contributors"
+ }
+ ],
+ "description": "📐 Nette Schema: validating data structures against a given Schema.",
+ "homepage": "https://nette.org",
+ "keywords": [
+ "config",
+ "nette"
+ ],
+ "time": "2019-04-03T15:53:25+00:00"
+ },
+ {
+ "name": "nette/utils",
+ "version": "v3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nette/utils.git",
+ "reference": "c133e18c922dcf3ad07673077d92d92cef25a148"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nette/utils/zipball/c133e18c922dcf3ad07673077d92d92cef25a148",
+ "reference": "c133e18c922dcf3ad07673077d92d92cef25a148",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "require-dev": {
+ "nette/tester": "~2.0",
+ "tracy/tracy": "^2.3"
+ },
+ "suggest": {
+ "ext-gd": "to use Image",
+ "ext-iconv": "to use Strings::webalize() and toAscii()",
+ "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()",
+ "ext-json": "to use Nette\\Utils\\Json",
+ "ext-mbstring": "to use Strings::lower() etc...",
+ "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()",
+ "ext-xml": "to use Strings::length() etc. when mbstring is not available"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause",
+ "GPL-2.0",
+ "GPL-3.0"
+ ],
+ "authors": [
+ {
+ "name": "David Grudl",
+ "homepage": "https://davidgrudl.com"
+ },
+ {
+ "name": "Nette Community",
+ "homepage": "https://nette.org/contributors"
+ }
+ ],
+ "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.",
+ "homepage": "https://nette.org",
+ "keywords": [
+ "array",
+ "core",
+ "datetime",
+ "images",
+ "json",
+ "nette",
+ "paginator",
+ "password",
+ "slugify",
+ "string",
+ "unicode",
+ "utf-8",
+ "utility",
+ "validation"
+ ],
+ "time": "2019-10-21T20:40:16+00:00"
+ },
+ {
+ "name": "nikic/php-parser",
+ "version": "v4.2.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nikic/PHP-Parser.git",
+ "reference": "b76bbc3c51f22c570648de48e8c2d941ed5e2cf2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/b76bbc3c51f22c570648de48e8c2d941ed5e2cf2",
+ "reference": "b76bbc3c51f22c570648de48e8c2d941ed5e2cf2",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "php": ">=7.0"
+ },
+ "require-dev": {
+ "ircmaxell/php-yacc": "0.0.4",
+ "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0"
+ },
+ "bin": [
+ "bin/php-parse"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.2-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PhpParser\\": "lib/PhpParser"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Nikita Popov"
+ }
+ ],
+ "description": "A PHP parser written in PHP",
+ "keywords": [
+ "parser",
+ "php"
+ ],
+ "time": "2019-10-25T18:33:07+00:00"
+ },
+ {
+ "name": "ocramius/package-versions",
+ "version": "1.5.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Ocramius/PackageVersions.git",
+ "reference": "1d32342b8c1eb27353c8887c366147b4c2da673c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Ocramius/PackageVersions/zipball/1d32342b8c1eb27353c8887c366147b4c2da673c",
+ "reference": "1d32342b8c1eb27353c8887c366147b4c2da673c",
+ "shasum": ""
+ },
+ "require": {
+ "composer-plugin-api": "^1.0.0",
+ "php": "^7.3.0"
+ },
+ "require-dev": {
+ "composer/composer": "^1.8.6",
+ "doctrine/coding-standard": "^6.0.0",
+ "ext-zip": "*",
+ "infection/infection": "^0.13.4",
+ "phpunit/phpunit": "^8.2.5",
+ "vimeo/psalm": "^3.4.9"
+ },
+ "type": "composer-plugin",
+ "extra": {
+ "class": "PackageVersions\\Installer",
+ "branch-alias": {
+ "dev-master": "1.6.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PackageVersions\\": "src/PackageVersions"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Marco Pivetta",
+ "email": "ocramius@gmail.com"
+ }
+ ],
+ "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)",
+ "time": "2019-07-17T15:49:50+00:00"
+ },
{
"name": "pdepend/pdepend",
"version": "2.6.1",
@@ -1810,6 +2491,128 @@
],
"time": "2019-10-03T11:07:50+00:00"
},
+ {
+ "name": "phpstan/phpdoc-parser",
+ "version": "0.3.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpstan/phpdoc-parser.git",
+ "reference": "8c4ef2aefd9788238897b678a985e1d5c8df6db4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/8c4ef2aefd9788238897b678a985e1d5c8df6db4",
+ "reference": "8c4ef2aefd9788238897b678a985e1d5c8df6db4",
+ "shasum": ""
+ },
+ "require": {
+ "php": "~7.1"
+ },
+ "require-dev": {
+ "consistence/coding-standard": "^3.5",
+ "jakub-onderka/php-parallel-lint": "^0.9.2",
+ "phing/phing": "^2.16.0",
+ "phpstan/phpstan": "^0.10",
+ "phpunit/phpunit": "^6.3",
+ "slevomat/coding-standard": "^4.7.2",
+ "squizlabs/php_codesniffer": "^3.3.2",
+ "symfony/process": "^3.4 || ^4.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "0.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PHPStan\\PhpDocParser\\": [
+ "src/"
+ ]
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "PHPDoc parser with support for nullable, intersection and generic types",
+ "time": "2019-06-07T19:13:52+00:00"
+ },
+ {
+ "name": "phpstan/phpstan",
+ "version": "0.11.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpstan/phpstan.git",
+ "reference": "63cc502f6957b7f74efbac444b4cf219dcadffd7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/63cc502f6957b7f74efbac444b4cf219dcadffd7",
+ "reference": "63cc502f6957b7f74efbac444b4cf219dcadffd7",
+ "shasum": ""
+ },
+ "require": {
+ "composer/xdebug-handler": "^1.3.0",
+ "jean85/pretty-package-versions": "^1.0.3",
+ "nette/bootstrap": "^2.4 || ^3.0",
+ "nette/di": "^2.4.7 || ^3.0",
+ "nette/neon": "^2.4.3 || ^3.0",
+ "nette/robot-loader": "^3.0.1",
+ "nette/schema": "^1.0",
+ "nette/utils": "^2.4.5 || ^3.0",
+ "nikic/php-parser": "^4.2.3",
+ "php": "~7.1",
+ "phpstan/phpdoc-parser": "^0.3.5",
+ "symfony/console": "~3.2 || ~4.0",
+ "symfony/finder": "~3.2 || ~4.0"
+ },
+ "conflict": {
+ "symfony/console": "3.4.16 || 4.1.5"
+ },
+ "require-dev": {
+ "brianium/paratest": "^2.0 || ^3.0",
+ "consistence/coding-standard": "^3.5",
+ "dealerdirect/phpcodesniffer-composer-installer": "^0.4.4",
+ "ext-intl": "*",
+ "ext-mysqli": "*",
+ "ext-simplexml": "*",
+ "ext-soap": "*",
+ "ext-zip": "*",
+ "jakub-onderka/php-parallel-lint": "^1.0",
+ "localheinz/composer-normalize": "^1.1.0",
+ "phing/phing": "^2.16.0",
+ "phpstan/phpstan-deprecation-rules": "^0.11",
+ "phpstan/phpstan-php-parser": "^0.11",
+ "phpstan/phpstan-phpunit": "^0.11",
+ "phpstan/phpstan-strict-rules": "^0.11",
+ "phpunit/phpunit": "^7.5.14 || ^8.0",
+ "slevomat/coding-standard": "^4.7.2",
+ "squizlabs/php_codesniffer": "^3.3.2"
+ },
+ "bin": [
+ "bin/phpstan"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "0.11-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PHPStan\\": [
+ "src/"
+ ]
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "PHPStan - PHP Static Analysis Tool",
+ "time": "2019-10-22T20:20:22+00:00"
+ },
{
"name": "phpunit/php-code-coverage",
"version": "6.0.5",
@@ -3228,6 +4031,55 @@
"homepage": "https://symfony.com",
"time": "2019-08-20T14:07:54+00:00"
},
+ {
+ "name": "symfony/finder",
+ "version": "v4.3.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/finder.git",
+ "reference": "5e575faa95548d0586f6bedaeabec259714e44d1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/5e575faa95548d0586f6bedaeabec259714e44d1",
+ "reference": "5e575faa95548d0586f6bedaeabec259714e44d1",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "4.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Finder\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Finder Component",
+ "homepage": "https://symfony.com",
+ "time": "2019-09-16T11:29:48+00:00"
+ },
{
"name": "symfony/polyfill-ctype",
"version": "v1.12.0",
diff --git a/docs/deprecated_wiki/Hosting-the-Database-Myself.md b/docs/deprecated_wiki/Hosting-the-Database-Myself.md
deleted file mode 100644
index 979870296cb..00000000000
--- a/docs/deprecated_wiki/Hosting-the-Database-Myself.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# Installing the Database - 1 of 2
-
-> **Before continuing:** MySQL must be installed and a `root` or admin-level MySQL user credential must be created before continuing. (This is not the same as a unix `root` credential.)
-
-1. Figure out your `` (It's probably the IP address of your remote machine)
-1. Open your internet browser
-1. Navigate to `/installdb.php`
-1. Fill in ``; if the MySQL server is on the same machine that is hosting Loris, it will be `localhost`
-1. Fill in ``; e.g. `root` -- must be an existing MySQL user
-1. Fill in ``
-1. Fill in ``; this database must not exist yet as the installer will try to create it
-1. Submit
-
-[[img/Installing-Loris-After-Installing-Prerequisites/install-db-admin-zoomed-4.png]]
-
-# Installing the Database - 2 of 2
-
-1. Fill in ``, ``; _recommended:_ `lorisuser`
-1. Fill in ``, ``; e.g. admin
-1. Submit
-
-[[img/Installing-Loris-After-Installing-Prerequisites/install-db-user-zoomed-4.png]]
-
-# Return to Installing Loris
-[Click here to continue with the next step: Logging into Loris](https://github.com/aces/Loris/wiki/Installing-Loris#logging-in-to-the-loris-admin-panel)
diff --git a/docs/deprecated_wiki/Hosting-the-Database-by-Others.md b/docs/deprecated_wiki/Hosting-the-Database-by-Others.md
deleted file mode 100644
index bf8850108e8..00000000000
--- a/docs/deprecated_wiki/Hosting-the-Database-by-Others.md
+++ /dev/null
@@ -1,20 +0,0 @@
-
diff --git a/docs/deprecated_wiki/Setup/Initial Setup/Security/Security:-Enabling-SSL.md b/docs/deprecated_wiki/Setup/Initial Setup/Security/Security-Enabling-SSL.md
similarity index 100%
rename from docs/deprecated_wiki/Setup/Initial Setup/Security/Security:-Enabling-SSL.md
rename to docs/deprecated_wiki/Setup/Initial Setup/Security/Security-Enabling-SSL.md
diff --git a/docs/wiki/00 - SERVER INSTALL AND CONFIGURATION/00 - Prerequisites And Assumptions/Database Configuration.md b/docs/wiki/00 - SERVER INSTALL AND CONFIGURATION/00 - Prerequisites And Assumptions/Database Configuration.md
new file mode 100644
index 00000000000..b965d3644c9
--- /dev/null
+++ b/docs/wiki/00 - SERVER INSTALL AND CONFIGURATION/00 - Prerequisites And Assumptions/Database Configuration.md
@@ -0,0 +1,30 @@
+# Database Configuration
+
+## Creating the Database
+MySQL or MariaDB must be installed and a `root` or admin-level user
+credential must be created before continuing. (This is not the same as a unix
+ `root` credential.)
+
+After running the install script, you will be prompted to visit the
+`installdb.php` page at the canonical domain of your LORIS instance.
+
+Completing the form on this page will create a new database and user account
+that will be used to execute transactions coming from LORIS's PHP code.
+
+## Administrative Account
+
+We recommend creating a separate administrative database account for sensitive
+transactions. In practice, this means creating and deleting new tables in the
+database. You'll need to do this when installing an instrument, for example.
+
+After creating this account, you can run the command below to give
+the administrative user the correct privileges.
+
+e.g. For a user named `lorisDBadmin` with password `newpassword`:
+
+```SQL
+GRANT ALTER, DROP, CREATE, UPDATE, INSERT, SELECT, DELETE, CREATE TEMPORARY TABLES, LOCK TABLES on $dbname.* to 'lorisDBadmin'@'$dbhost' IDENTIFIED BY 'newpassword' WITH GRANT OPTION;
+```
+
+This user's credentials should now be entered into your project's configuration file, `config.xml`
+within the `adminUser` and `adminPassword` tags.
diff --git a/docs/wiki/00 - SERVER INSTALL AND CONFIGURATION/01 - LORIS Install/CentOS/README.CentOS7.md b/docs/wiki/00 - SERVER INSTALL AND CONFIGURATION/01 - LORIS Install/CentOS/README.md
similarity index 100%
rename from docs/wiki/00 - SERVER INSTALL AND CONFIGURATION/01 - LORIS Install/CentOS/README.CentOS7.md
rename to docs/wiki/00 - SERVER INSTALL AND CONFIGURATION/01 - LORIS Install/CentOS/README.md
diff --git a/htdocs/acknowledgements/acknowledgements.php b/htdocs/acknowledgements/acknowledgements.php
index a859e6f7672..9abfd32e965 100644
--- a/htdocs/acknowledgements/acknowledgements.php
+++ b/htdocs/acknowledgements/acknowledgements.php
@@ -26,7 +26,6 @@
$columns = array(
'full_name' => 'Full Name',
'citation_name' => 'Citation Name',
- 'title' => 'Title',
'affiliations' => 'Affiliations',
'degrees' => 'Degrees',
'roles' => 'Roles',
diff --git a/jsx/Form.js b/jsx/Form.js
index 3a17f9300b8..d67d464bc7f 100644
--- a/jsx/Form.js
+++ b/jsx/Form.js
@@ -478,7 +478,7 @@ class SelectElement extends Component {
// element will take up the whole row.
let label = null;
let inputClass = 'col-sm-12';
- if (this.props.label || this.props.label == '') {
+ if (this.props.label && this.props.label != '') {
label = (
-
{this.props.text}
+
{this.props.text}
);
@@ -1442,6 +1442,7 @@ StaticElement.propTypes = {
StaticElement.defaultProps = {
label: '',
text: null,
+ class: 'form-control-static',
};
/**
diff --git a/mkdocs.yml b/mkdocs.yml
index 2ad87a38b90..eede634a030 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -5,6 +5,7 @@ nav:
- Wiki: 'wiki/index.md'
- Server Install and Configuration:
- 'Prerequisities and Assumptions': 'wiki/00 - SERVER INSTALL AND CONFIGURATION/00 - Prerequisites And Assumptions/README.md'
+ - 'Database Configuration': 'wiki/00 - SERVER INSTALL AND CONFIGURATION/00 - Prerequisites And Assumptions/Database Configuration.md'
- Installation:
- 'Ubuntu Install': 'wiki/00 - SERVER INSTALL AND CONFIGURATION/01 - LORIS Install/Ubuntu/README.md'
- 'CentOS Install': 'wiki/00 - SERVER INSTALL AND CONFIGURATION/01 - LORIS Install/CentOS/README.md'
diff --git a/modules/acknowledgements/php/acknowledgements.class.inc b/modules/acknowledgements/php/acknowledgements.class.inc
index 94d4899cdc0..c03876bed5b 100644
--- a/modules/acknowledgements/php/acknowledgements.class.inc
+++ b/modules/acknowledgements/php/acknowledgements.class.inc
@@ -192,7 +192,7 @@ class Acknowledgements extends \NDB_Menu_Filter_Form
*
* @return string JSON
*/
- function toJSON()
+ function toJSON(): string
{
$config = \NDB_Config::singleton();
diff --git a/modules/behavioural_qc/test/TestPlan.md b/modules/behavioural_qc/test/TestPlan.md
index cde28615df9..a7eb3a21e1e 100644
--- a/modules/behavioural_qc/test/TestPlan.md
+++ b/modules/behavioural_qc/test/TestPlan.md
@@ -10,13 +10,12 @@
'access_all_profiles' permission or 'All User Sites' otherwise.
3. Remove the 'access all profiles' permission and test whether the site filter is
now populated only with sites that are study sites and to which the user has access.
-4. Make sure that the user accessible site data is only populated with the step 4 condition.
+4. Make sure that the user accessible site data is only populated with the step 3 condition.
5. Ensure that Conflict/Incomplete Candidate/Link to BVL Feedback links point to the correct place.
6. Ensure that feedback status is correct.
7. Ensure that the behavioural_qc graphics is working according to the applied filters.
-8. Click on a field label and ensure that it downloads CSV of the data.
-9. Repeat steps 2-9 with applying all the filters.
-10. Perform a query that returns a row with a link to BVL feedback. Click on the click to edit the feedback QC
+8. Repeat steps 2-9 with applying all the filters.
+9. Perform a query that returns a row with a link to BVL feedback. Click on the click to edit the feedback QC
status and change its value. Save the data and close the popup. Make sure that the behavioural_qc result table has been
updated for that row (i.e. reflect the new Feedback status). Click on the feedback link again and check that
the QC status has also been updated in the popup window.
diff --git a/modules/candidate_parameters/ajax/formHandler.php b/modules/candidate_parameters/ajax/formHandler.php
index 134eb5a3252..42f99e8fd3e 100644
--- a/modules/candidate_parameters/ajax/formHandler.php
+++ b/modules/candidate_parameters/ajax/formHandler.php
@@ -55,6 +55,10 @@
editConsentStatusFields($db, $user);
break;
+case 'candidateDOB':
+ editCandidateDOB($db, $user);
+ break;
+
default:
header("HTTP/1.1 404 Not Found");
exit;
@@ -525,3 +529,32 @@ function editConsentStatusFields($db, $user)
}
}
}
+
+/**
+ * Handles the updating of candidate's date of birth.
+ *
+ * @param Database $db database object
+ * @param User $user user object
+ *
+ * @throws DatabaseException
+ *
+ * @return void
+ */
+function editCandidateDOB(\Database $db, \User $user): void
+{
+ $candID = new CandID($_POST['candID']);
+ $dob = $_POST['dob'];
+ $strippedDate = null;
+ if (!empty($dob)) {
+ $config = \NDB_Config::singleton();
+ $dobFormat = $config->getSetting('dobFormat');
+ if ($dobFormat === 'YM') {
+ $strippedDate = date("Y-m", strtotime($dob))."-01";
+ }
+ $db->update(
+ 'candidate',
+ array('DoB' => $strippedDate ?? $dob),
+ array('CandID' => $candID->__toString())
+ );
+ }
+}
diff --git a/modules/candidate_parameters/ajax/getData.php b/modules/candidate_parameters/ajax/getData.php
index 22db2a61bdb..b95c2ea8904 100644
--- a/modules/candidate_parameters/ajax/getData.php
+++ b/modules/candidate_parameters/ajax/getData.php
@@ -48,6 +48,9 @@
case 'consentStatus':
echo json_encode(getConsentStatusFields());
exit;
+case 'candidateDOB':
+ echo json_encode(getDOBFields());
+ exit;
default:
header("HTTP/1.1 404 Not Found");
exit;
@@ -492,3 +495,27 @@ function getConsentStatusHistory($pscid)
}
return $formattedHistory;
}
+
+/**
+ * Handles the fetching of candidate's date of birth.
+ *
+ * @return array
+ */
+function getDOBFields(): array
+{
+ $candID = new CandID($_GET['candID']);
+ $db = \Database::singleton();
+ // Get PSCID
+ $candidateData = $db->pselectRow(
+ 'SELECT PSCID,DoB FROM candidate where CandID =:candid',
+ array('candid' => $candID->__toString())
+ );
+ $pscid = $candidateData['PSCID'] ?? null;
+ $dob = $candidateData['DoB'] ?? null;
+ $result = [
+ 'pscid' => $pscid,
+ 'candID' => $candID->__toString(),
+ 'dob' => $dob,
+ ];
+ return $result;
+}
diff --git a/modules/candidate_parameters/jsx/CandidateDOB.js b/modules/candidate_parameters/jsx/CandidateDOB.js
new file mode 100644
index 00000000000..f46abba837a
--- /dev/null
+++ b/modules/candidate_parameters/jsx/CandidateDOB.js
@@ -0,0 +1,170 @@
+import React, {Component} from 'react';
+import PropTypes from 'prop-types';
+import Loader from 'Loader';
+
+class CandidateDOB extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ data: {},
+ formData: {
+ dob: null,
+ },
+ error: false,
+ isLoaded: false,
+ };
+
+ this.fetchData = this.fetchData.bind(this);
+ this.setFormData = this.setFormData.bind(this);
+ this.handleSubmit = this.handleSubmit.bind(this);
+ }
+
+ componentDidMount() {
+ this.fetchData()
+ .then(() => this.setState({isLoaded: true}));
+ }
+
+ fetchData() {
+ return fetch(this.props.dataURL, {credentials: 'same-origin'})
+ .then((resp) => resp.json())
+ .then((data) => this.setState({data: data, formData: data}))
+ .catch((error) => {
+ this.setState({error: true});
+ console.error(error);
+ });
+ }
+
+ setFormData(formElement, value) {
+ let formData = this.state.formData;
+ formData[formElement] = value;
+ this.setState({
+ formData: formData,
+ });
+ }
+
+ render() {
+ if (this.state.error) {
+ return