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

An error occured while loading the page.

; + } + + if (!this.state.isLoaded) { + return ; + } + + let disabled = true; + let updateButton = null; + if (loris.userHasPermission('candidate_dob_edit')) { + disabled = false; + updateButton = ; + } + return ( +
+ + + + + + {updateButton} + +
+ ); + } + + /** + * Handles form submission + * + * @param {event} e - Form submission event + */ + handleSubmit(e) { + e.preventDefault(); + + let today = new Date(); + let dd = String(today.getDate()).padStart(2, '0'); + let mm = String(today.getMonth() + 1).padStart(2, '0'); // January is 0! + let yyyy = today.getFullYear(); + today = yyyy + '-' + mm + '-' + dd; + + let dob = this.state.formData.dob ? + this.state.formData.dob : null; + if (dob > today) { + swal({ + title: 'Error!', + text: 'Date of birth cannot be later than today!', + type: 'error', + confrimButtonText: 'OK', + }); + return; + } + // Set form data and upload the media file + let formData = this.state.formData; + let formObject = new FormData(); + for (let key in formData) { + if (formData.hasOwnProperty(key)) { + if (formData[key] !== '') { + formObject.append(key, formData[key]); + } + } + } + + formObject.append('tab', this.props.tabName); + + fetch(this.props.action, { + method: 'POST', + cache: 'no-cache', + credentials: 'same-origin', + body: formObject, + }) + .then((resp) => { + if (resp.ok && resp.status === 200) { + swal({ + title: 'Success!', + text: 'Date of birth updated!', + type: 'success', + confrimButtonText: 'OK', + }); + if (result.value) { + this.fetchData(); + } + } else { + swal({ + title: 'Error!', + text: 'Something went wrong.', + type: 'error', + confrimButtonText: 'OK', + }); + } + }) + .catch((error) => { + console.error(error); + }); + } +} +CandidateDOB.propTypes = { + dataURL: PropTypes.string, + tabName: PropTypes.string, + action: PropTypes.string, +}; +export default CandidateDOB; diff --git a/modules/candidate_parameters/jsx/CandidateParameters.js b/modules/candidate_parameters/jsx/CandidateParameters.js index a9dfdd5f464..2c745cf7232 100644 --- a/modules/candidate_parameters/jsx/CandidateParameters.js +++ b/modules/candidate_parameters/jsx/CandidateParameters.js @@ -5,6 +5,7 @@ import ProbandInfo from './ProbandInfo'; import FamilyInfo from './FamilyInfo'; import ParticipantStatus from './ParticipantStatus'; import ConsentStatus from './ConsentStatus'; +import CandidateDOB from './CandidateDOB'; import {Tabs, TabPane} from 'Tabs'; class CandidateParameters extends Component { @@ -35,6 +36,7 @@ class CandidateParameters extends Component { let tabList = [ {id: 'candidateInfo', label: 'Candidate Information', component: CandidateInfo}, {id: 'participantStatus', label: 'Participant Status', component: ParticipantStatus}, + {id: 'candidateDOB', label: 'Date of Birth', component: CandidateDOB}, ]; if (loris.config('useProband') === 'true') { diff --git a/modules/configuration/tools/import_projects.php b/modules/configuration/tools/import_projects.php index 78c515ea907..5433ec0148e 100644 --- a/modules/configuration/tools/import_projects.php +++ b/modules/configuration/tools/import_projects.php @@ -25,9 +25,14 @@ $client = new NDB_Client(); $client->makeCommandLine(); $client->initialize(); -$factory = NDB_Factory::singleton(); -$config = $factory->config(__DIR__ . "/../../../project/config.xml"); -$subprojs = $config->getSettingFromXML("subprojects"); +$factory = NDB_Factory::singleton(); +$config = $factory->config(__DIR__ . "/../../../project/config.xml"); +$subprojs = $config->getSettingFromXML("subprojects"); +if (!is_array($subprojs)) { + throw new \ConfigurationException( + 'Config setting "Projects" must be an array' + ); +} $db = $factory->database(); $optionpos = 1; //The position of the option in the command line. @@ -69,7 +74,12 @@ ) { $config = $factory->config(__DIR__ . "/../../../project/config.xml"); $projects = $config->getSettingFromXML("Projects"); - $db = $factory->database(); + if (!is_array($projects)) { + throw new \ConfigurationException( + 'Config setting "Projects" must be an array' + ); + } + $db = $factory->database(); foreach ($projects['project'] as $row) { $insert = array( 'ProjectID' => $row['id'], diff --git a/modules/conflict_resolver/php/conflict_resolver.class.inc b/modules/conflict_resolver/php/conflict_resolver.class.inc index cef465f982a..98cc5bdf3ef 100644 --- a/modules/conflict_resolver/php/conflict_resolver.class.inc +++ b/modules/conflict_resolver/php/conflict_resolver.class.inc @@ -384,7 +384,7 @@ class Conflict_Resolver extends \NDB_Menu_Filter_Form * * @return string a json encoded string of the headers and data from this table */ - function toJSON() + function toJSON(): string { $result = $this->toArray(); $result['form'] = $this->form->form; diff --git a/modules/conflict_resolver/php/resolved_conflicts.class.inc b/modules/conflict_resolver/php/resolved_conflicts.class.inc index 29bf2b66af6..abb835a3088 100644 --- a/modules/conflict_resolver/php/resolved_conflicts.class.inc +++ b/modules/conflict_resolver/php/resolved_conflicts.class.inc @@ -230,7 +230,7 @@ class Resolved_Conflicts extends \NDB_Menu_Filter * * @return string a json encoded string of the headers and data from this table */ - function toJSON() + function toJSON(): string { $result = $this->toArray(); $result['form'] = $this->form->form; diff --git a/modules/conflict_resolver/test/TestPlan.md b/modules/conflict_resolver/test/TestPlan.md index 85912aae282..a8d9ee35122 100644 --- a/modules/conflict_resolver/test/TestPlan.md +++ b/modules/conflict_resolver/test/TestPlan.md @@ -31,7 +31,7 @@ - Select the right Site - Select the right Project - Select the right Visit-label - - Check that buttons work: 'Show Data', 'Clear Form' + - Check that 'Clear Form' removes values from the filters and resets the table - Verify that filters work as expected - inspect the results table 6. Operation of resolving conflict and saving data should work as follows:[Automation Testing] - On Unresolved conflicts tab, set value of dropdown lists to accepted value @@ -41,7 +41,6 @@ - Press 'Save' button to save. Page will reload Ensure the changes take effect: - Check database to verify that submitted values have been properly saved - - Click on 'Show Data' And the conflict should not longer appear - Also check and make sure that the instrument and its corresponding DDE are updated accordingly - Ensure if Date_taken is changed, the candidate age in the instrument is updated accordingly - Make sure the scoring_fields are re-calculated in the given instrument once the conflict is resolved diff --git a/modules/data_release/ajax/AddPermission.php b/modules/data_release/ajax/AddPermission.php index 14d8ef35021..96e81ecb75d 100644 --- a/modules/data_release/ajax/AddPermission.php +++ b/modules/data_release/ajax/AddPermission.php @@ -76,7 +76,6 @@ '', '', '', - '' ); $vFiles = $data_release->getVersionedFiles($DB); $prePermissions = $data_release->getUserVersionPermissions($vFiles, $DB); diff --git a/modules/datadict/jsx/dataDictIndex.js b/modules/datadict/jsx/dataDictIndex.js index 41f74cbfc1e..63ab2f344b2 100644 --- a/modules/datadict/jsx/dataDictIndex.js +++ b/modules/datadict/jsx/dataDictIndex.js @@ -1,5 +1,7 @@ -import FilterForm from 'FilterForm'; +import React, {Component} from 'react'; +import PropTypes from 'prop-types'; import Loader from 'Loader'; +import FilterableDataTable from 'FilterableDataTable'; /** * Data Dictionary Page. @@ -14,71 +16,38 @@ import Loader from 'Loader'; * @version 1.0.0 * * */ -class DataDictIndex extends React.Component { +class DataDictIndex extends Component { constructor(props) { super(props); this.state = { + data: {}, + error: false, isLoaded: false, - filter: {}, - hiddenHeaders: [], }; - /** - * Set filter to the element's ref for filtering - */ - this.filter = null; - this.setFilterRef = (element) => { - this.filter = element; - }; - - /** - * Bind component instance to custom methods - */ this.fetchData = this.fetchData.bind(this); - this.updateFilter = this.updateFilter.bind(this); - this.resetFilters = this.resetFilters.bind(this); this.formatColumn = this.formatColumn.bind(this); } componentDidMount() { - this.fetchData(); + this.fetchData() + .then( () => this.setState({isLoaded: true})); } /** * Retrive data from the provided URL and save it in state - * Additionaly add hiddenHeaders to global loris variable - * for easy access by columnFormatter. + * + * @return {object} */ fetchData() { - $.ajax(this.props.DataURL, { - method: 'GET', - dataType: 'json', - success: (data) => { - this.setState({ - data: data, - isLoaded: true, + return fetch(this.props.dataURL, {credentials: 'same-origin'}) + .then((resp) => resp.json()) + .then((data) => this.setState({data})) + .catch((error) => { + this.setState({error: true}); + console.error(error); }); - }, - error: (error) => console.error(error), - }); - } - - /** - * Set this.state.filter to the input filter object - * - * @param {object} filter - the filter object - */ - updateFilter(filter) { - this.setState({filter}); - } - - // TODO: deprecate clearing filters via refs in future refactoring. - /** - * Reset the filter elements with textInput refs to empty values - */ - resetFilters() { - this.filter.clearFilter(); } /** @@ -92,9 +61,6 @@ class DataDictIndex extends React.Component { * @return {*} a formated table cell for a given column */ formatColumn(column, cell, rowData, rowHeaders) { - if (this.state.hiddenHeaders.indexOf(column) > -1) { - return null; - } const hasEditPermission = loris.userHasPermission('data_dict_edit'); if (column === 'Description' && hasEditPermission) { let updateDict = (name) => { @@ -111,7 +77,7 @@ class DataDictIndex extends React.Component { + onBlur={updateDict(rowData.Name)}> {cell} ); @@ -120,45 +86,84 @@ class DataDictIndex extends React.Component { } render() { + if (this.state.error) { + return

An error occured while loading the page.

; + } + // Waiting for async data to load if (!this.state.isLoaded) { return ; } + let options = this.state.data.fieldOptions; + let fields = [ + { + label: 'Source From', + show: true, + filter: { + name: 'Source From', + type: 'select', + options: options.sourceFrom, + }, + }, + { + label: 'Name', + show: true, + filter: { + name: 'Name', + type: 'text', + }, + }, + { + label: 'Source Field', + show: true, + filter: { + name: 'Source Field', + type: 'text', + }, + }, + { + label: 'Description', + show: true, + filter: { + name: 'Description', + type: 'text', + }, + }, + { + label: 'Description Status', + show: true, + filter: { + name: 'DescriptionStatus', + type: 'select', + options: { + 'empty': 'Empty', + 'modified': 'Modified', + 'unchanged': 'Unchanged', + }, + }, + }, + ]; return ( -
- - - - -
); } } -$(function() { - const dataDictIndex = ( -
- -
+DataDictIndex.propTypes = { + dataURL: PropTypes.string.isRequired, +}; + +window.addEventListener('load', () => { + ReactDOM.render( + , + document.getElementById('lorisworkspace') ); - ReactDOM.render(dataDictIndex, document.getElementById('lorisworkspace')); }); - diff --git a/modules/datadict/php/datadict.class.inc b/modules/datadict/php/datadict.class.inc index 30e82caf387..12841d36290 100644 --- a/modules/datadict/php/datadict.class.inc +++ b/modules/datadict/php/datadict.class.inc @@ -2,7 +2,7 @@ /** * Datadict module * - * PHP version 5 + * PHP version 7 * * @category Datadict * @package Main @@ -14,7 +14,7 @@ namespace LORIS\datadict; /** * Datadict module * - * PHP version 5 + * PHP version 7 * * @category Datadict * @package Main @@ -23,11 +23,8 @@ namespace LORIS\datadict; * @link https://github.com/aces/Loris-Trunk */ -class Datadict extends \NDB_Menu_Filter +class Datadict extends \DataFrameworkMenu { - var $AjaxModule = true; - var $skipTemplate = true; - /** * Overloading this method to allow access to site users (their own site * only) and users w/ multisite privs @@ -43,147 +40,38 @@ class Datadict extends \NDB_Menu_Filter } /** - * Setup variables function + * The data dictionary has no sites affiliated with it and as + * such can not add site filters without an exception being + * thrown * - * @note Setup variables function - * @return string - */ - function _buildQuery(): string - { - $select = " SELECT DISTINCT - pt.sourceFrom as source_from, - pt.name as name, - pt.sourceField as source_field, - coalesce(pto.description,pt.description) as description, - CASE - WHEN COALESCE(pto.description,pt.description) = '' THEN 'Empty' - WHEN pto.name IS NOT NULL THEN 'Modified' - WHEN pto.name IS NULL THEN 'Unchanged' - END as description_status "; - - $joins = " FROM parameter_type pt - LEFT JOIN parameter_type_override pto USING (Name) - WHERE pt.Queryable=1 "; - $query = $select . $joins; - return $query; - } - - /** - * Setup variables function - * - * @return void + * @return bool */ - function _setupVariables() + public function useSiteFilter() : bool { - $query = $this->_buildQuery(); - $this->query = " FROM (" . $query . ") as tmp"; - - $this->formToFilter = array( - 'sourceFrom' => 'pt.sourceFrom', - 'description' => 'pt.Description', - ); - - $this->searchKeyword = array( - 'pt.Name', - 'pt.sourceField', - 'pto.description', - ); - // set the class variables - - $this->columns = array( - 'source_from', - 'name', - 'source_field', - 'description', - 'description_status', - ); - - $this->headers = array( - 'Source From', - 'Name', - 'Source Field', - 'Description', - 'Description Status', - ); + return false; } /** - * Set Filter Form + * Returns a list of instruments to use as the "Source From" + * filter options * - * @return void + * @return array Dynamic field options */ - function setup() + public function getFieldOptions() : array { - parent::setup(); - - // list of feedback statuses - $instruments = \Utility::getAllInstruments(); - $this->addSelect( - 'sourceFrom', - 'Instruments', - $instruments, - array('multiple') + return array( + 'sourceFrom' => \Utility::getAllInstruments(), ); - $this->addSelect( - 'descriptionStatus', - 'Description Status', - array( - 'empty' => 'Empty', - 'modified' => 'Modified', - 'unchanged' => 'Unchanged', - ) - ); - $this->addBasicText('keyword', "Search keyword"); - } - - /** - * Add query filters - * - * @param string $prepared_key the query string - * @param string $key the key of filter - * @param string $val the value of filter - * - * @note Get base query - * @return string - * @access private - */ - function _addValidFilters($prepared_key, $key, $val) - { - $query = ''; - if ((!empty($val) || $val === '0') && $key != 'order') { - // special rule for dropdowns where value is numeric - if (strtolower(substr($key, -8)) == 'centerid' - || strtolower(substr($key, -10)) == 'categoryid' - || strtolower(substr($key, -6)) == 'sex' - ) { - $query .= " AND $key = '$val' "; - } else { - if ($val == 'empty') { - $query .= " AND COALESCE(pto.description,pt.description) = ''"; - } elseif ($val=='modified') { - $query .= " AND pto.name IS NOT NULL"; - } elseif ($val=='unmodified') { - $query .= " AND pto.name IS NULL"; - } else { - $query .= " AND $key LIKE '$val%' "; - } - } - } - return $query; } - /** - * Converts the results of this menu filter to a JSON format to be retrieved - * with ?format=json + * Gets the data source for this menu filter. * - * @return string a json encoded string of the headers and data from this table + * @return \LORIS\Data\Provisioner */ - function toJSON() : string + public function getBaseDataProvisioner() : \LORIS\Data\Provisioner { - $result = $this->toArray(); - $result['form'] = $this->form->form; - return json_encode($result); + return new DataDictRowProvisioner(); } /** @@ -216,4 +104,14 @@ class Datadict extends \NDB_Menu_Filter new \LORIS\Breadcrumb('Data Dictionary', "/$this->name") ); } + + /** + * The datadict module does not have any concept of a project. + * + * @return bool + */ + public function useProjectFilter() : bool + { + return false; + } } diff --git a/modules/datadict/php/datadictrow.class.inc b/modules/datadict/php/datadictrow.class.inc new file mode 100644 index 00000000000..2c0cab26cde --- /dev/null +++ b/modules/datadict/php/datadictrow.class.inc @@ -0,0 +1,52 @@ + + * @license http://www.gnu.org/licenses/gpl-3.0.txt GPLv3 + * @link https://www.github.com/aces/Loris/ + */ + +namespace LORIS\datadict; + +/** + * A DataDictRow represents a row in the datadict menu table. + * + * @category Behavioural + * @package Main + * @subpackage Behavioural + * @author Dave MacFarlane + * @license http://www.gnu.org/licenses/gpl-3.0.txt GPLv3 + * @link https://www.github.com/aces/Loris/ + */ +class DataDictRow implements \LORIS\Data\DataInstance +{ + protected $DBRow; + + /** + * Create a new DataDictRow + * + * @param array $row The row (in the same format as \Database::pselectRow + * returns + */ + public function __construct(array $row) + { + $this->DBRow = $row; + } + + /** + * Implements \LORIS\Data\DataInstance interface for this row. + * + * @return string the row data. + */ + public function toJSON() : string + { + return json_encode($this->DBRow); + } +} diff --git a/modules/datadict/php/datadictrowprovisioner.class.inc b/modules/datadict/php/datadictrowprovisioner.class.inc new file mode 100644 index 00000000000..426e5fb6f88 --- /dev/null +++ b/modules/datadict/php/datadictrowprovisioner.class.inc @@ -0,0 +1,70 @@ + + * @license http://www.gnu.org/licenses/gpl-3.0.txt GPLv3 + * @link https://www.github.com/aces/Loris/ + */ + +namespace LORIS\datadict; + +/** + * This class implements a data provisioner to get all possible rows + * for the datadict menu page. + * + * PHP Version 7 + * + * @category Behavioural + * @package Main + * @subpackage Behavioural + * @author Dave MacFarlane + * @license http://www.gnu.org/licenses/gpl-3.0.txt GPLv3 + * @link https://www.github.com/aces/Loris/ + */ +class DataDictRowProvisioner extends \LORIS\Data\Provisioners\DBRowProvisioner +{ + /** + * Create a DataDictRowProvisioner, which gets rows for + * the datadict menu table. + */ + function __construct() + { + parent::__construct( + "SELECT DISTINCT + pt.sourceFrom as source_from, + pt.name as name, + pt.sourceField as source_field, + coalesce(pto.description,pt.description) as description, + CASE + WHEN COALESCE(pto.description,pt.description) = '' THEN 'Empty' + WHEN pto.name IS NOT NULL THEN 'Modified' + WHEN pto.name IS NULL THEN 'Unchanged' + END as description_status + FROM parameter_type pt + LEFT JOIN parameter_type_override pto USING (Name) + WHERE pt.Queryable=1 + ", + array() + ); + } + + /** + * Returns an instance of a DataDict object for a given + * table row. + * + * @param array $row The database row from the LORIS Database class. + * + * @return \LORIS\Data\DataInstance An instance representing this row. + */ + public function getInstance($row) : \LORIS\Data\DataInstance + { + return new DataDictRow($row); + } +} diff --git a/modules/datadict/test/datadictTest.php b/modules/datadict/test/datadictTest.php index f71a600e0d7..f6ec5a4a38d 100644 --- a/modules/datadict/test/datadictTest.php +++ b/modules/datadict/test/datadictTest.php @@ -88,7 +88,7 @@ function testDatadictDoespageLoad() $this->webDriver->wait(120, 1000)->until( WebDriverExpectedCondition::presenceOfElementLocated( - WebDriverBy::Name("keyword") + WebDriverBy::Name("Name") ) ); @@ -97,71 +97,6 @@ function testDatadictDoespageLoad() )->getText(); $this->assertContains("Data Dictionary", $bodyText); } - /** - * Testing keyword filter with testing data - * - * @return void - */ - function testDataDictSearchKeywordFilters() - { - $this->safeGet($this->url . "/datadict/"); - - $searchKey = $this->webDriver->findElements( - WebDriverBy::Name("keyword") - ); - - $searchKey[0]->sendKeys("NotRealMAGICNUMBER335"); - - $name = $this->webDriver->executescript( - "return document.querySelector". - "('#dynamictable > tbody > tr > td:nth-child(3)').textContent" - ); - $this->assertContains("TestParameterNotRealMAGICNUMBER335", $name); - } - /** - * Testing keyword filter with testing data not case-sensitive - * - * @return void - */ - function testDataDictSearchKeywordFiltersnotCaseSensitvie() - { - $this->safeGet($this->url . "/datadict/"); - - $searchKey = $this->webDriver->findElements( - WebDriverBy::Name("keyword") - ); - - $searchKey[0]->sendKeys("notrealMAGICNUMBER335"); - - $name = $this->webDriver->executescript( - "return document.querySelector". - "('#dynamictable > tbody > tr > td:nth-child(3)').textContent" - ); - $this->assertContains("TestParameterNotRealMAGICNUMBER335", $name); - } - /** - * Testing keyword filter without testing data - * - * @return void - */ - function testDataDictSearchKeywordFiltersWithoutData() - { - $this->safeGet($this->url . "/datadict/"); - - $searchKey = $this->webDriver->findElements( - WebDriverBy::Name("keyword") - ); - - $searchKey[0]->sendKeys("noExist"); - - $res = $this->webDriver->executescript( - "return document.querySelector". - "('#lorisworkspace > div > div > div.panel.panel-default >". - "div.table-header.panel-heading > div > div').textContent" - ); - $this->assertContains("0 rows displayed", $res); - } - /** * Testing UI elements when page loads * diff --git a/modules/dicom_archive/php/viewdetails.class.inc b/modules/dicom_archive/php/viewdetails.class.inc index edb841f12cd..3986b57c20f 100644 --- a/modules/dicom_archive/php/viewdetails.class.inc +++ b/modules/dicom_archive/php/viewdetails.class.inc @@ -323,7 +323,7 @@ class ViewDetails extends \NDB_Form * @return string name of the protocol, "Unknown" if * protocol with the given id doesn't exist. */ - function _getProtocolNameFromID($id) + function _getProtocolNameFromID($id): string { try { $query = "SELECT Scan_type FROM mri_scan_type WHERE ID=:ID"; diff --git a/modules/document_repository/php/document_repository.class.inc b/modules/document_repository/php/document_repository.class.inc index 7291aca5f78..b76c35d9696 100644 --- a/modules/document_repository/php/document_repository.class.inc +++ b/modules/document_repository/php/document_repository.class.inc @@ -185,7 +185,7 @@ class Document_Repository extends \NDB_Menu_Filter_Form * * @return string a json encoded string of the headers and data from this table */ - function toJSON() + function toJSON(): string { $result = $this->toArray(); $result['maxUploadSize'] = \Utility::getMaxUploadSize(); diff --git a/modules/examiner/php/examiner.class.inc b/modules/examiner/php/examiner.class.inc index 2381fffe393..47427f4a7d1 100644 --- a/modules/examiner/php/examiner.class.inc +++ b/modules/examiner/php/examiner.class.inc @@ -339,7 +339,7 @@ class Examiner extends \NDB_Menu_Filter_Form * * @return string JSON */ - function toJSON() + function toJSON(): string { $result = $this->toArray(); $result['form'] = $this->form->form; diff --git a/modules/help_editor/php/help_editor.class.inc b/modules/help_editor/php/help_editor.class.inc index 327bd73b199..fe328f2bafb 100644 --- a/modules/help_editor/php/help_editor.class.inc +++ b/modules/help_editor/php/help_editor.class.inc @@ -56,7 +56,7 @@ class Help_Editor extends \NDB_Menu_Filter * * @return string a json encoded string of the headers and data from this table */ - function toJSON() + function toJSON(): string { $table = (new \LORIS\Data\Table()) ->withDataFrom($this->getDataProvisioner()); diff --git a/modules/imaging_uploader/php/imaging_uploader.class.inc b/modules/imaging_uploader/php/imaging_uploader.class.inc index 7bf06b1adc0..5fcd21e9c6a 100644 --- a/modules/imaging_uploader/php/imaging_uploader.class.inc +++ b/modules/imaging_uploader/php/imaging_uploader.class.inc @@ -755,7 +755,7 @@ class Imaging_Uploader extends \NDB_Menu_Filter_Form * * @return string json encoded string of the headers and data from this table */ - function toJSON() + function toJSON(): string { $result = $this->toArray(); $result['form'] = $this->form->form; diff --git a/modules/instrument_manager/php/instrument_manager.class.inc b/modules/instrument_manager/php/instrument_manager.class.inc index e40ebc84af1..967a23908c0 100644 --- a/modules/instrument_manager/php/instrument_manager.class.inc +++ b/modules/instrument_manager/php/instrument_manager.class.inc @@ -70,7 +70,7 @@ class Instrument_Manager extends \NDB_Menu_Filter $this->factory = \NDB_Factory::singleton(); $this->path = $this->factory->config()->getSetting("base"); - parent::__construct($module, $page, $id, $commentID, $formname); + parent::__construct($module, $page, $id, $commentID); } /** diff --git a/modules/issue_tracker/php/issue_tracker.class.inc b/modules/issue_tracker/php/issue_tracker.class.inc index 6f1db08ff60..c4fbaf202c0 100644 --- a/modules/issue_tracker/php/issue_tracker.class.inc +++ b/modules/issue_tracker/php/issue_tracker.class.inc @@ -73,7 +73,7 @@ class Issue_Tracker extends \NDB_Menu_Filter_Form * * @return string a json encoded string of the headers and data from this table */ - function toJSON() + function toJSON(): string { $user = \User::singleton(); $db = \Database::singleton(); diff --git a/modules/user_accounts/php/edit_user.class.inc b/modules/user_accounts/php/edit_user.class.inc index 21138cd5c47..5c472862dcb 100644 --- a/modules/user_accounts/php/edit_user.class.inc +++ b/modules/user_accounts/php/edit_user.class.inc @@ -1085,7 +1085,14 @@ class Edit_User extends \NDB_Form //================================== // Password validation //================================== - if ($values['Email'] === $values['Password_hash']) { + + // Make sure the user is not using their email address as their password. + // Do not show this error if the password is an empty string: in this + // case, that means the email is empty also. It's more appropriate to + // display only the error 'You must enter an email'. + if ($values['Email'] === $values['Password_hash'] + && $values['Password_hash'] !== '' + ) { $errors['Password_Group'] = self::PASSWORD_ERROR_IS_EMAIL; } if (!is_null($this->identifier)) { diff --git a/php/libraries/BVL_Feedback_Panel.class.inc b/php/libraries/BVL_Feedback_Panel.class.inc index d78cf100d28..60c1d13e409 100644 --- a/php/libraries/BVL_Feedback_Panel.class.inc +++ b/php/libraries/BVL_Feedback_Panel.class.inc @@ -33,9 +33,16 @@ class BVL_Feedback_Panel /** * The feedback thread that this panel is for * - * @var NDB_BVL_Feedback + * @protected NDB_BVL_Feedback */ - var $_feedbackThread; + protected $feedbackThread; + + /** + * An array containing data that will be passed to the Smarty template. + * + * @public array + */ + public $tpl_data; /** * Creates the feedback thread for the given combination of candID, @@ -51,7 +58,7 @@ class BVL_Feedback_Panel ?string $commentID=null ) { - $this->_feedbackThread + $this->feedbackThread = \NDB_BVL_Feedback::singleton( \User::singleton()->getUsername(), $candID, @@ -70,7 +77,7 @@ class BVL_Feedback_Panel */ function display(): string { - $feedbackProfile = $this->_feedbackThread->_feedbackCandidateProfileInfo; + $feedbackProfile = $this->feedbackThread->_feedbackCandidateProfileInfo; $candidateID = new CandID($feedbackProfile["CandID"]); $this->tpl_data['candID'] = (string) $candidateID; @@ -80,16 +87,16 @@ class BVL_Feedback_Panel $this->tpl_data['sessionID'] = $feedbackProfile["SessionID"] ?? null; - $feedbackObject = $this->_feedbackThread->_feedbackObjectInfo; + $feedbackObject = $this->feedbackThread->_feedbackObjectInfo; $this->tpl_data['commentID'] = $feedbackObject["CommentID"] ?? null; - $this->tpl_data['thread_list'] = $this->_feedbackThread->getThreadList(); - $this->tpl_data['feedback_level'] = $this->_feedbackThread->_feedbackLevel; + $this->tpl_data['thread_list'] = $this->feedbackThread->getThreadList(); + $this->tpl_data['feedback_level'] = $this->feedbackThread->_feedbackLevel; $this->tpl_data['feedback_types'] = NDB_BVL_Feedback::getFeedbackTypes(); $this->tpl_data['feedbacktypes'] = NDB_BVL_Feedback::getFeedbackTypes(); - $summary = $this->_feedbackThread->getSummaryOfThreads(); + $summary = $this->feedbackThread->getSummaryOfThreads(); $this->tpl_data['thread_summary_headers'] = json_encode($summary); $field_names = Utility::getSourcefields($_REQUEST['test_name'] ?? ''); @@ -101,7 +108,7 @@ class BVL_Feedback_Panel $this->tpl_data['FieldNames'] = json_encode($fields); - $smarty = new Smarty_neurodb("bvl_feedback_panel"); + $smarty = new Smarty_NeuroDB("bvl_feedback_panel"); $smarty->assign($this->tpl_data); $html = $smarty->fetch("bvl_feedback_panel.tpl"); return $html; diff --git a/php/libraries/Candidate.class.inc b/php/libraries/Candidate.class.inc index 68b8cc423bc..48e54ba2065 100644 --- a/php/libraries/Candidate.class.inc +++ b/php/libraries/Candidate.class.inc @@ -157,7 +157,7 @@ class Candidate trim($_REQUEST['PSCID']) ) != strtolower($this->getPSCID()) ) { - throw new LorisException("IDs do not match"); + throw new \LorisException("IDs do not match"); } } diff --git a/php/libraries/CouchDB.class.inc b/php/libraries/CouchDB.class.inc index b0eb2492db9..253f74d4ad0 100644 --- a/php/libraries/CouchDB.class.inc +++ b/php/libraries/CouchDB.class.inc @@ -23,6 +23,9 @@ */ class SocketWrapper { + public $host; + public $port; + public $socket; /** * Constructor for SocketWrapper */ @@ -186,13 +189,19 @@ class CouchDB /** * Boolean true if we are currently doing a bulk transaction. */ - var $bulk = false; + public $bulk = false; /** * Array of documents to be commited when the current bulk transaction * ends. */ - var $bulkDocuments = array(); + public $bulkDocuments = array(); + + /** + * An instance of SocketWrapper used in network interaction with a CouchDB + * database. + */ + public $SocketHandler; /** * Private Constructor for CouchDB diff --git a/php/libraries/DataFrameworkMenu.class.inc b/php/libraries/DataFrameworkMenu.class.inc index db069565e91..badbe30fd9d 100644 --- a/php/libraries/DataFrameworkMenu.class.inc +++ b/php/libraries/DataFrameworkMenu.class.inc @@ -45,16 +45,14 @@ abstract class DataFrameworkMenu extends NDB_Menu_Filter * @param string $page The subtest being accessed (may be an empty string) * @param string $identifier The identifier for the data to load on this page * @param string $commentID The CommentID to load the data for - * @param string $formname The name to give this form */ public function __construct( \Module $module, string $page, string $identifier, - string $commentID, - string $formname + string $commentID ) { - parent::__construct($module, $page, $identifier, $commentID, $formname); + parent::__construct($module, $page, $identifier, $commentID); $this->AjaxModule = true; $this->skipTemplate = true; @@ -130,7 +128,7 @@ abstract class DataFrameworkMenu extends NDB_Menu_Filter * * @return string a json encoded string of the headers and data from this table */ - public function toJSON() + public function toJSON(): string { $table = (new \LORIS\Data\Table()) ->withDataFrom($this->getDataProvisionerWithFilters()); diff --git a/php/libraries/Database.class.inc b/php/libraries/Database.class.inc index 1a50a137999..7e79a89553d 100644 --- a/php/libraries/Database.class.inc +++ b/php/libraries/Database.class.inc @@ -58,6 +58,13 @@ class Database var $_preparedStoreHistory; + /** + * The name of the database. Used internally for printing log messages. + * + * @access private + */ + private $_databaseName = ''; + /** * Singleton design pattern implementation - creates the object * and also connects to the database if necessary. @@ -1462,4 +1469,3 @@ class Database ); } } - diff --git a/php/libraries/Email.class.inc b/php/libraries/Email.class.inc index 2618e9af448..fa97687417c 100644 --- a/php/libraries/Email.class.inc +++ b/php/libraries/Email.class.inc @@ -94,7 +94,7 @@ class Email } // populate the template - $smarty = new Smarty_neurodb; + $smarty = new Smarty_NeuroDB; $smarty->assign($tpl_data); $message = $smarty->fetch('email/' . $template); diff --git a/php/libraries/File_Upload.class.inc b/php/libraries/File_Upload.class.inc index 22981889bd2..6495cd0a000 100644 --- a/php/libraries/File_Upload.class.inc +++ b/php/libraries/File_Upload.class.inc @@ -26,26 +26,36 @@ */ class File_Upload { + public $renameMode = "incremental"; + public $overwriteMode = "rename"; + public $fileMove = true; + public $fileVerify = true; + public $fileImport = true; + public $filenamePrefix = ""; + public $createDirectories = true; + public $errorLog = array(); + public $moveOrCopy = "move"; + public $isCLImport = false; + public $handlerArgs; + public $file; + public $fileInfo; + public $fileHandlers; + public $destinationDirectory; + public $destinationFilename; + public $fieldName; + public $fieldNames; + public $CLFiles; + public $form; + public $baseUploadDirectory; + private $_seeded; /** * Construct the File_Upload class. This sets the default parameters * for a file which can be overwritten by calling the set* methods */ function __construct() { - //Set Defaults - $this->renameMode = "incremental"; - $this->overwriteMode = "rename"; - $this->fileMove = true; - $this->fileVerify = true; - $this->fileImport = true; - $this->filenamePrefix = ""; - $this->createDirectories = true; - $this->errorLog = array(); - $this->moveOrCopy = "move"; - $this->isCLImport = false; } - /** * Loops through the uploaded files running the full suit of functions against * them. diff --git a/php/libraries/IdentifierGenerator.php b/php/libraries/IdentifierGenerator.php index 76acaaa122f..5841f486eba 100644 --- a/php/libraries/IdentifierGenerator.php +++ b/php/libraries/IdentifierGenerator.php @@ -33,7 +33,9 @@ abstract class IdentifierGenerator protected $length; protected $minValue; protected $maxValue; - protected $siteAlias = ''; + protected $prefix; + protected $siteAlias = ''; + protected $projectAlias = ''; /** * Generates a new unused identifier to represent a Candidate in LORIS. @@ -65,7 +67,21 @@ protected function createNewID(): string break; } - // Return padded value with appropriate prefix + if (!empty($this->siteAlias) && !empty($this->projectAlias)) { + throw new \InvalidArgumentException( + 'Only one of siteAlias or projectAlias should have a value' + ); + } + if (empty($this->siteAlias) && empty($this->projectAlias)) { + throw new \InvalidArgumentException( + 'Either siteAlias or projectAlias must not be empty' + ); + } + // Assign class property 'prefix' to whichever alias is not empty. + !empty($this->siteAlias) ? + $this->prefix = $this->siteAlias + : $this->prefix = $this->projectAlias; + return $this->prefix . $id; } diff --git a/php/libraries/LorisForm.class.inc b/php/libraries/LorisForm.class.inc index 6f1f0d76f27..a81cb7cd899 100644 --- a/php/libraries/LorisForm.class.inc +++ b/php/libraries/LorisForm.class.inc @@ -49,6 +49,8 @@ class LorisForm 'email', 'maxlength', ); + public $validOperators; + public $encrypt; /** * Creates and returns an element that can be added @@ -1033,7 +1035,7 @@ class LorisForm function timeHTML($el, $type='time') { $timeStamp = $this->getValue($el['name']); - $smarty = new Smarty_neurodb; + $smarty = new Smarty_NeuroDB; $value = array( 'H' => null, 'i' => null, @@ -1077,7 +1079,7 @@ class LorisForm function yearHTML($el) { $year = $this->getValue($el['name']); - $smarty = new Smarty_neurodb; + $smarty = new Smarty_NeuroDB; $value = explode('-', $year)[0]; $smarty->assign('name', $el['name']); @@ -1729,7 +1731,7 @@ class LorisForm function toHTML() { - $smarty = new Smarty_neurodb; + $smarty = new Smarty_NeuroDB; $formArray = $this->toElementArray(); $smarty->assign('form', $formArray); diff --git a/php/libraries/MRIFile.class.inc b/php/libraries/MRIFile.class.inc index 96ff8e2c39e..415f8aedcb5 100644 --- a/php/libraries/MRIFile.class.inc +++ b/php/libraries/MRIFile.class.inc @@ -22,9 +22,11 @@ */ class MRIFile { - var $fileData = array(); - var $parameters = array(); - var $QCData = array(); + public $fileData = array(); + public $parameters = array(); + public $QCData = array(); + public $intermFiles = array(); + public $protFiles = array(); /** * Construct an MRIFile diff --git a/php/libraries/Module.class.inc b/php/libraries/Module.class.inc index 79ef0dfce28..31934f26f92 100644 --- a/php/libraries/Module.class.inc +++ b/php/libraries/Module.class.inc @@ -228,7 +228,8 @@ abstract class Module extends \LORIS\Router\PrefixRouter * * @param string $page The name of the page within the module to load. * - * @return a NDB_Page subclass representing this page. + * @return NDB_Page + * Returns NDB_Page (or subclass) representing this page. */ public function loadPage(string $page) { diff --git a/php/libraries/NDB_BVL_Battery.class.inc b/php/libraries/NDB_BVL_Battery.class.inc index 091ec7d163c..b3b59a26b7c 100644 --- a/php/libraries/NDB_BVL_Battery.class.inc +++ b/php/libraries/NDB_BVL_Battery.class.inc @@ -34,7 +34,9 @@ class NDB_BVL_Battery * * @access private */ - var $sessionID = null; + public $sessionID = null; + + public $age; /** * Constructor - merely asserts that the environment is suitable @@ -381,10 +383,11 @@ class NDB_BVL_Battery */ public static function getInstrumentNameForCommentId($commentId) { - return \Database::singleton()->pselectOne( - "SELECT Test_name FROM flag WHERE CommentID=:CID", - array('CID' => $commentId) - ); + return \NDB_Factory::singleton()->database() + ->pselectOne( + "SELECT Test_name FROM flag WHERE CommentID=:CID", + array('CID' => $commentId) + ); } /** diff --git a/php/libraries/NDB_BVL_Feedback.class.inc b/php/libraries/NDB_BVL_Feedback.class.inc index 28ac30e207d..cf171c2bd04 100644 --- a/php/libraries/NDB_BVL_Feedback.class.inc +++ b/php/libraries/NDB_BVL_Feedback.class.inc @@ -340,7 +340,7 @@ class NDB_BVL_Feedback return ''; } - $smarty = new Smarty_neurodb; + $smarty = new Smarty_NeuroDB; // What does this do? $smarty->ConfigLoad('default.conf', 'bvlqc'); return $smarty->getConfigVars($status); diff --git a/php/libraries/NDB_BVL_Instrument.class.inc b/php/libraries/NDB_BVL_Instrument.class.inc index 54eca327a9e..7dd9fdedd83 100644 --- a/php/libraries/NDB_BVL_Instrument.class.inc +++ b/php/libraries/NDB_BVL_Instrument.class.inc @@ -42,7 +42,14 @@ abstract class NDB_BVL_Instrument extends NDB_Page * * @access private */ - var $form; + public $form; + + public $formType; + + public $dateOptions; + public $DataEntryType; + public $XINRules; + public $XINDebug; /** * Test name (short name), equivalent to test_names.Test_name @@ -216,8 +223,7 @@ abstract class NDB_BVL_Instrument extends NDB_Page Module::factory("instruments"), $page, $commentID, - $commentID, - 'test_form' + $commentID ); } else { if (!class_exists($class) @@ -472,7 +478,7 @@ abstract class NDB_BVL_Instrument extends NDB_Page $this->form->setDefaults($defaults); if ($this->DataEntryType == 'DirectEntry') { - $smarty = new Smarty_neurodb; + $smarty = new Smarty_NeuroDB; $formArray = $this->form->toElementArray(); if (isset($this->testName)) { @@ -489,7 +495,7 @@ abstract class NDB_BVL_Instrument extends NDB_Page // not the display function. return $this->toJSON(); } else { - $smarty = new Smarty_neurodb; + $smarty = new Smarty_NeuroDB; $formArray = $this->form->toElementArray(); $smarty->assign('form', $formArray); @@ -1492,7 +1498,7 @@ abstract class NDB_BVL_Instrument extends NDB_Page { $sessionID = $this->getSessionID(); if ($sessionID !== -1) { - $timepoint = \Timepoint::singleton($sessionID); + $timepoint = \TimePoint::singleton($sessionID); $subprojectID = $timepoint->getSubprojectID(); return $subprojectID; } @@ -2343,7 +2349,7 @@ abstract class NDB_BVL_Instrument extends NDB_Page { $DB = Database::singleton(); - $smarty = new Smarty_neurodb(); + $smarty = new Smarty_NeuroDB(); $tpl_data = array(); $tpl_data['questions'] = $DB->pselect( @@ -2544,17 +2550,7 @@ abstract class NDB_BVL_Instrument extends NDB_Page */ function _toJSONParsePage(): array { - - if (get_class($this->form) === 'LorisForm') { - $formArray = $this->form->toElementArray(); - } else { - $smarty = new Smarty_neurodb; - $renderer = new HTML_QuickForm_Renderer_Array($smarty); - - $this->form->accept($renderer); - - $formArray = $renderer->toArray(); - } + $formArray = $this->form->toElementArray(); if (isset($formArray['elements'])) { foreach ($formArray['elements'] as &$element) { @@ -2587,7 +2583,7 @@ abstract class NDB_BVL_Instrument extends NDB_Page */ function toJSON(): string { - $smarty = new Smarty_neurodb; + $smarty = new Smarty_NeuroDB; //$renderer = new HTML_QuickForm_Renderer_Array($smarty); $subtests = $this->getSubtestList(); @@ -2600,7 +2596,6 @@ abstract class NDB_BVL_Instrument extends NDB_Page ); } $this->page = $subtest['Name']; - $this->_setupForm(); } $formArray = $this->_toJSONParsePage(); diff --git a/php/libraries/NDB_BVL_InstrumentStatus_ControlPanel.class.inc b/php/libraries/NDB_BVL_InstrumentStatus_ControlPanel.class.inc index b494d45dd3a..49a0378d75c 100644 --- a/php/libraries/NDB_BVL_InstrumentStatus_ControlPanel.class.inc +++ b/php/libraries/NDB_BVL_InstrumentStatus_ControlPanel.class.inc @@ -26,7 +26,10 @@ use LORIS\StudyEntities\Candidate\CandID; */ class NDB_BVL_InstrumentStatus_ControlPanel extends NDB_BVL_InstrumentStatus { - + public $tpl_data; + public $validityEnabled; + public $validityRequired; + protected $instrument; /** * Construct a controller for the instrument status control panel * @@ -93,10 +96,10 @@ class NDB_BVL_InstrumentStatus_ControlPanel extends NDB_BVL_InstrumentStatus $this->subtest ?? '' ); - $this->_instrument = $instrument; + $this->instrument = $instrument; - $this->ValidityEnabled = $instrument->ValidityEnabled; - $this->ValidityRequired = $instrument->ValidityRequired; + $this->validityEnabled = $instrument->validityEnabled; + $this->validityRequired = $instrument->validityRequired; // generate the subtest list $list = $instrument->getSubtestList(); @@ -119,7 +122,7 @@ class NDB_BVL_InstrumentStatus_ControlPanel extends NDB_BVL_InstrumentStatus = $this->_displayDataEntry(); // generate the validity flag buttons - if ($this->ValidityEnabled == true) { + if ($this->validityEnabled == true) { $this->tpl_data['access']['validity'] = $this->_displayValidity(); } @@ -133,7 +136,7 @@ class NDB_BVL_InstrumentStatus_ControlPanel extends NDB_BVL_InstrumentStatus } } - $smarty = new Smarty_neurodb; + $smarty = new Smarty_NeuroDB; $smarty->assign($this->tpl_data); $html = $smarty->fetch("instrumentstatus_controlpanel.tpl"); return $html; @@ -221,7 +224,7 @@ class NDB_BVL_InstrumentStatus_ControlPanel extends NDB_BVL_InstrumentStatus $showLink = true; $Validity = $this->getValidityStatus(); if ($Validity == null - && $this->_instrument->ValidityRequired == true + && $this->instrument->validityRequired == true && $this->getAdministrationStatus() != 'None' ) { $showLink = false; @@ -233,10 +236,10 @@ class NDB_BVL_InstrumentStatus_ControlPanel extends NDB_BVL_InstrumentStatus && $this->getAdministrationStatus() == 'All' ) { // run the data entry logic test - if (isset($this->_instrument)) { + if (isset($this->instrument)) { if ($showLink == true) { $CompStatus - = $this->_instrument->getDataEntryCompletionStatus(); + = $this->instrument->getDataEntryCompletionStatus(); $showLink = $CompStatus == 'Complete'; } @@ -411,4 +414,3 @@ class NDB_BVL_InstrumentStatus_ControlPanel extends NDB_BVL_InstrumentStatus return (!$timePoint->isSubmitted() || $maxThreadStatus == 'opened'); } } - diff --git a/php/libraries/NDB_BVL_Instrument_LINST.class.inc b/php/libraries/NDB_BVL_Instrument_LINST.class.inc index 8570b4f6f27..b81e3ed6c5e 100644 --- a/php/libraries/NDB_BVL_Instrument_LINST.class.inc +++ b/php/libraries/NDB_BVL_Instrument_LINST.class.inc @@ -30,11 +30,13 @@ class NDB_BVL_Instrument_LINST extends \NDB_BVL_Instrument */ use \LegacyInstrumentTrait; - var $InstrumentType = 'LINST'; + public $InstrumentType = 'LINST'; - var $LinstQuestions = array(); + public $LinstQuestions = array(); - var $LinstLines = array(); + public $LinstLines = array(); + + private $_selectMultipleElements; /** * Sets up the variables required for a LINST instrument to load @@ -386,9 +388,8 @@ class NDB_BVL_Instrument_LINST extends \NDB_BVL_Instrument $db = \Database::singleton(); if (!isset($this->form)) { - $this->form = new \HTML_Quickform('test_form'); + $this->form = new \LorisForm(); } - $this->dateTimeFields = array("Date_taken"); $this->formType = 'XIN'; diff --git a/php/libraries/NDB_BVL_Instrument_instrument_preview.class.inc b/php/libraries/NDB_BVL_Instrument_instrument_preview.class.inc index 21e79167741..cea2a694141 100644 --- a/php/libraries/NDB_BVL_Instrument_instrument_preview.class.inc +++ b/php/libraries/NDB_BVL_Instrument_instrument_preview.class.inc @@ -39,7 +39,7 @@ class NDB_BVL_Instrument_Instrument_Preview $this->commentID = $commentID; $this->page = $page; - $this->form = new \HTML_Quickform('test_form'); + $this->form = new \LorisForm(); $this->loadInstrumentFile( "data:text/plain;base64," . base64_encode($_REQUEST['instrumentdata']), diff --git a/php/libraries/NDB_Caller.class.inc b/php/libraries/NDB_Caller.class.inc index 62d899a9b75..5dcccf6089b 100644 --- a/php/libraries/NDB_Caller.class.inc +++ b/php/libraries/NDB_Caller.class.inc @@ -30,7 +30,11 @@ class NDB_Caller * * @var string */ - var $type; + public $type; + + public $page; + public $controlPanel; + public $feedbackPanel; /** * Determines how data entry is being performed (directly from a study diff --git a/php/libraries/NDB_Form.class.inc b/php/libraries/NDB_Form.class.inc index ecd6455dfab..70e332b9a81 100644 --- a/php/libraries/NDB_Form.class.inc +++ b/php/libraries/NDB_Form.class.inc @@ -206,10 +206,9 @@ class NDB_Form extends NDB_Page } /** - * Converts the results of this form to a JSON format to be retrieved - * with ?format=json + * {@inheritDoc} * - * @return string a json encoded string of the options to send to the form + * @return string */ function toJSON(): string { diff --git a/php/libraries/NDB_Menu.class.inc b/php/libraries/NDB_Menu.class.inc index 7d0baf56949..43569f39d55 100644 --- a/php/libraries/NDB_Menu.class.inc +++ b/php/libraries/NDB_Menu.class.inc @@ -46,16 +46,14 @@ class NDB_Menu extends NDB_Page * @param string $page The subtest being accessed (may be null) * @param string $identifier The identifier for the data to load on this page * @param string $commentID The CommentID to load the data for - * @param string $formname The name to give this form */ public function __construct( \Module $module, string $page, string $identifier, - string $commentID, - string $formname + string $commentID ) { - parent::__construct($module, $page, $identifier, $commentID, $formname); + parent::__construct($module, $page, $identifier, $commentID); $this->menu = $module->getName(); } /** @@ -115,11 +113,20 @@ class NDB_Menu extends NDB_Page return ""; } // dump the html for the menu - $smarty = new Smarty_neurodb($this->Module->getName()); + $smarty = new Smarty_NeuroDB($this->Module->getName()); $smarty->assign('mode', $this->mode); $smarty->assign($this->getTemplateData()); $html = $smarty->fetch("menu_$this->menu.tpl"); return $html; } -} + /** + * {@inheritDoc} + * + * @return string + */ + function toJSON(): string + { + return json_encode(array('error' => 'Not implemented')); + } +} diff --git a/php/libraries/NDB_Menu_Filter.class.inc b/php/libraries/NDB_Menu_Filter.class.inc index 97f1ae760d0..a178a638c75 100644 --- a/php/libraries/NDB_Menu_Filter.class.inc +++ b/php/libraries/NDB_Menu_Filter.class.inc @@ -695,7 +695,7 @@ class NDB_Menu_Filter extends NDB_Menu */ // dump the html for the menu - $smarty = new Smarty_neurodb($this->Module->getName()); + $smarty = new Smarty_NeuroDB($this->Module->getName()); $smarty->assign('mode', $this->mode); $smarty->assign('form', $this->form->toArray()); $smarty->assign($this->getTemplateData()); @@ -804,7 +804,7 @@ class NDB_Menu_Filter extends NDB_Menu * * @return string a json encoded string of the headers and data from this table */ - function toJSON() + function toJSON(): string { return json_encode($this->toArray()); } diff --git a/php/libraries/NDB_Page.class.inc b/php/libraries/NDB_Page.class.inc index e975c56362e..11b7a8160b9 100644 --- a/php/libraries/NDB_Page.class.inc +++ b/php/libraries/NDB_Page.class.inc @@ -70,6 +70,9 @@ class NDB_Page implements RequestHandlerInterface */ var $fieldOptions = array(); + public $Module; + public $template; + /** * The format that the page content should be returned in. This is generally * the value of the `?format=` GET parameter from the request, and is usually @@ -97,14 +100,12 @@ class NDB_Page implements RequestHandlerInterface * @param string $page The subtest being accessed (may be an empty string) * @param string $identifier The identifier for the data to load on this page * @param string $commentID The CommentID to load the data for - * @param string $formname The name to give this form */ function __construct( \Module $module, string $page, string $identifier, - string $commentID, - string $formname + string $commentID ) { $this->Module = $module; $this->name = $module->getName(); // for legacy purposes. @@ -664,7 +665,7 @@ class NDB_Page implements RequestHandlerInterface RequestHandlerInterface $handler ) : ResponseInterface { $user = $request->getAttribute("user"); - if ($this->_hasAccess($user ?? new AnonymousUser()) !== true) { + if ($this->_hasAccess($user ?? new \LORIS\AnonymousUser()) !== true) { return (new \LORIS\Middleware\PageDecorationMiddleware($user)) ->process( $request, @@ -749,7 +750,7 @@ class NDB_Page implements RequestHandlerInterface $this->form->applyFilter('__ALL__', 'trim'); // display the HTML_Quickform object - $smarty = new Smarty_neurodb($this->name); + $smarty = new Smarty_NeuroDB($this->name); $smarty->ModuleName = $this->name; @@ -904,5 +905,15 @@ class NDB_Page implements RequestHandlerInterface new \LORIS\Breadcrumb($sublabel, "/$this->name/$this->page") ); } -} + /** + * Converts the results of this form to a JSON format to be retrieved + * with ?format=json + * + * @return string a json encoded string of the options to send to the form + */ + function toJSON(): string + { + return json_encode(array('error' => 'Not implemented')); + } +} diff --git a/php/libraries/SessionID.php b/php/libraries/SessionID.php index e113a0e63c8..36fd02fa917 100644 --- a/php/libraries/SessionID.php +++ b/php/libraries/SessionID.php @@ -50,9 +50,9 @@ public function getType(): string */ protected function validate(string $value): bool { - return (intval($value) > 0) - && (strlen($value) <= self::SESSIONID_MAX_LENGTH) - && (is_integer($value)); + return intval($value) > 0 + && strlen($value) <= self::SESSIONID_MAX_LENGTH + && ctype_digit($value); } /** diff --git a/php/libraries/SiteIDGenerator.php b/php/libraries/SiteIDGenerator.php index 2458f47fc47..a5eb99715d5 100644 --- a/php/libraries/SiteIDGenerator.php +++ b/php/libraries/SiteIDGenerator.php @@ -24,9 +24,9 @@ */ class SiteIDGenerator extends IdentifierGenerator { - /* Either 'PSCID' or 'ExternalID' */ private const LENGTH = 4; + /* Either 'PSCID' or 'ExternalID' */ protected $kind; protected $siteAlias; protected $projectAlias; @@ -53,17 +53,24 @@ public function __construct(string $siteAlias, string $projectAlias) // Initialize minimum and maximum allowed values for IDs. Set the values // to the lowest/highest character in $alphabet repeated $length times // if the min or max is not configured in project/config.xml - $this->minValue = $this->_getIDSetting('min') ?? - str_repeat(strval($this->alphabet[0]), $this->length); + $this->maxValue = $this->_getIDSetting('max') ?? + str_repeat(strval($this->alphabet[0]), intval($this->length)); + if (!is_array($this->alphabet)) { + throw new \ConfigurationException( + 'Expecting variable $alphabet to be an array but got ' + . gettype($this->alphabet) + ); + } $this->maxValue = $this->_getIDSetting('max') ?? str_repeat( strval($this->alphabet[count($this->alphabet) - 1]), - $this->length + intval($this->length) ); $this->siteAlias = $siteAlias; $this->projectAlias = $projectAlias; - $this->prefix = $this->_getIDSetting('prefix'); + + $this->prefix = $this->_getIDSetting('prefix'); $this->validate(); } diff --git a/php/libraries/Smarty_hook.class.inc b/php/libraries/Smarty_hook.class.inc index f45b57246b0..60091b3b95f 100644 --- a/php/libraries/Smarty_hook.class.inc +++ b/php/libraries/Smarty_hook.class.inc @@ -1,6 +1,6 @@ /dev/null +find docs modules htdocs php src tools -name '*.class.inc' -print0 -o -name '*.php' -print0 |xargs -0 -n1 php -l >/dev/null # Run PHPCS on all .php and .inc files in folders: # php/ # htdocs/ # modules/ -vendor/bin/phpcs --standard=test/LorisCS.xml --extensions=php,inc php/ htdocs/ modules/ || exit $?; -# Run PHPCS on some scripts -- fixing the files format later -# vendor/bin/phpcs --standard=docs/LorisCS.xml tools/CouchDB_Confirm_Integrity.php +# Also run PHPCS on all tools/ scripts in this array +declare -a tools_list=( + 'assign_missing_instruments.php' + 'setconfig.php' +) +vendor/bin/phpcs --standard=test/LorisCS.xml --extensions=php,inc php/ htdocs/ modules/ "${tools_list[@]/#/tools/}" || exit $?; # Run PHPCS on src/ directory using a different ruleset conforming to PSR2. vendor/bin/phpcs --standard=test/SrcCS.xml --extensions=php/php src/ || exit $?; vendor/bin/phpmd php/,modules/,src/ text 'test/LorisPHPMD.xml' || exit $?; + +# Run PHPStan on php/ and modules/ +vendor/bin/phpstan analyse --level max -c ./test/phpstan-loris.neon --error-format table php/ modules/ || exit $? diff --git a/test/unittests/NDB_PageTest.php b/test/unittests/NDB_PageTest.php index 53da0652adc..14b4bb25590 100644 --- a/test/unittests/NDB_PageTest.php +++ b/test/unittests/NDB_PageTest.php @@ -48,7 +48,7 @@ protected function setUp() $this->_module = new NullModule("test_module"); $this->_page = new NDB_Page( - $this->_module, "test_page", "515", "123", "test_form" + $this->_module, "test_page", "515", "123" ); } diff --git a/tools/assign_missing_instruments.php b/tools/assign_missing_instruments.php index b8895cc5443..016044c86b1 100755 --- a/tools/assign_missing_instruments.php +++ b/tools/assign_missing_instruments.php @@ -120,14 +120,13 @@ function populateVisitLabel($result, $visit_label) print_r($diff); } if ($confirm === true) { - foreach ($diff AS $test_name) { + foreach ($diff as $test_name) { $battery->addInstrument($test_name); } } unset($battery); unset($timePoint); - } if (isset($visit_label)) { @@ -138,7 +137,7 @@ function populateVisitLabel($result, $visit_label) $where = array('vl' => $argv[1]); $results = $DB->pselect($query, $where); - foreach ($results AS $result) { + foreach ($results as $result) { populateVisitLabel($result, $visit_label); } } else if (isset($visit_labels)) { @@ -146,7 +145,7 @@ function populateVisitLabel($result, $visit_label) LEFT JOIN candidate c USING (CandID) WHERE s.Active='Y' AND c.Active='Y' AND s.Visit_label NOT LIKE 'Vsup%'"; $results = $DB->pselect($query, array()); - foreach ($results AS $result) { + foreach ($results as $result) { populateVisitLabel($result, $result['Visit_label']); } } @@ -155,4 +154,3 @@ function populateVisitLabel($result, $visit_label) echo "\n\nRun this tool again with the argument 'confirm' to ". "perform the changes\n\n"; } -?> diff --git a/tools/lorisform_parser.php b/tools/lorisform_parser.php index 5b556f33e24..94df4ca60be 100755 --- a/tools/lorisform_parser.php +++ b/tools/lorisform_parser.php @@ -54,7 +54,7 @@ echo "Requiring file...\n"; include_once $file; echo "Instantiating new object...\n"; - $obj =new $className(new Module("", ""), "", "", "", ""); + $obj =new $className(new NullModule(), "", "", "", ""); echo "Initializing instrument object...\n"; $obj->setup(null, null); diff --git a/tools/setconfig.php b/tools/setconfig.php index 60e3886b3f1..3b51f7903a2 100755 --- a/tools/setconfig.php +++ b/tools/setconfig.php @@ -26,11 +26,11 @@ const MIN_NUMBER_OF_ARGS = 3; $args = $argv; if ($args[0] == 'php') { - $args = array_slice($argv, 1); + $args = array_slice($argv, 1); } if (count($args) < MIN_NUMBER_OF_ARGS) { - fwrite(STDERR, "Usage: setconfig.php setting value\n"); - exit(2); + fwrite(STDERR, "Usage: setconfig.php setting value\n"); + exit(2); } $setting = $args[1]; @@ -61,7 +61,7 @@ array('id' => $id) ); -if($newconfig === 0) { +if ($newconfig === 0) { $DB->insert("Config", array('Value' => $value, 'ConfigID' => $id)); } else { $DB->update("Config", array('Value' => $value), array('ConfigID' => $id));