diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0a8b686f57c..6050cfe6c4f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,9 @@ changes in the following format: PR #1234***
#### Features
- Added new interface intended to be used for querying module data from PHP (PR #8215)
- Added the NOT NULL constraint on Project Name (PR #8295)
+- Migrated instrument permissions from config.xml to database and added the ability
+ to manage instrument permissions in the frontend from the `instrument_manager`
+ module. (PR #8302)
#### Updates and Improvements
- Rename subproject to Cohort (PR #7817)
diff --git a/Makefile b/Makefile
index a7f0dc14533..658abc7e79c 100755
--- a/Makefile
+++ b/Makefile
@@ -52,8 +52,12 @@ check: checkstatic unittests
testdata:
php tools/raisinbread_refresh.php
+instrument_manager:
+ target=instrument_manager npm run compile
+
login:
target=login npm run compile
mri_violations:
target=mri_violations npm run compile
+
diff --git a/SQL/0000-00-02-Permission.sql b/SQL/0000-00-02-Permission.sql
index c7ed19b6f5f..8ebca54b267 100644
--- a/SQL/0000-00-02-Permission.sql
+++ b/SQL/0000-00-02-Permission.sql
@@ -152,3 +152,11 @@ CREATE TABLE `notification_modules_perm_rel` (
INSERT INTO notification_modules_perm_rel SELECT nm.id, p.permID FROM notification_modules nm JOIN permissions p WHERE nm.module_name='media' AND (p.code='media_write' OR p.code='media_read');
INSERT INTO notification_modules_perm_rel SELECT nm.id, p.permID FROM notification_modules nm JOIN permissions p WHERE nm.module_name='document_repository' AND (p.code='document_repository_view' OR p.code='document_repository_delete');
INSERT INTO notification_modules_perm_rel SELECT nm.id, p.permID FROM notification_modules nm JOIN permissions p WHERE nm.module_name='publication' AND (p.code='publication_view' OR p.code='publication_propose' OR p.code='publication_approve');
+
+CREATE TABLE `testnames_permissions_rel` (
+ `TestID` int(10) unsigned NOT NULL,
+ `permID` int(10) unsigned NOT NULL,
+ PRIMARY KEY (`TestID`,`permID`),
+ CONSTRAINT `FK_testnames_permissions_rel_test` FOREIGN KEY (`TestID`) REFERENCES `test_names` (`ID`),
+ CONSTRAINT `FK_testnames_permissions_rel_perm` FOREIGN KEY (`permID`) REFERENCES `permissions` (`permID`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
diff --git a/SQL/New_patches/2022-12-20-instrumentpermissions.sql b/SQL/New_patches/2022-12-20-instrumentpermissions.sql
new file mode 100644
index 00000000000..27a127c8a64
--- /dev/null
+++ b/SQL/New_patches/2022-12-20-instrumentpermissions.sql
@@ -0,0 +1,7 @@
+CREATE TABLE `testnames_permissions_rel` (
+ `TestID` int(10) unsigned NOT NULL,
+ `permID` int(10) unsigned NOT NULL,
+ PRIMARY KEY (`TestID`,`permID`),
+ CONSTRAINT `FK_testnames_permissions_rel_test` FOREIGN KEY (`TestID`) REFERENCES `test_names` (`ID`),
+ CONSTRAINT `FK_testnames_permissions_rel_perm` FOREIGN KEY (`permID`) REFERENCES `permissions` (`permID`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
diff --git a/docs/config/config.xml b/docs/config/config.xml
index 7f9e4cf5277..476e47501f6 100644
--- a/docs/config/config.xml
+++ b/docs/config/config.xml
@@ -70,33 +70,6 @@
Instrument Display Name
-
-
-
-
-
- false
-
-
-
- sampleInstrument
-
- sampleInstrumentPermissionName
-
-
- sampleInstrument2
- sampleInstrument2PermissionName
-
-
-
diff --git a/modules/instrument_manager/jsx/instrumentManagerIndex.js b/modules/instrument_manager/jsx/instrumentManagerIndex.js
index a9ff5b373ef..78fdecb74b2 100644
--- a/modules/instrument_manager/jsx/instrumentManagerIndex.js
+++ b/modules/instrument_manager/jsx/instrumentManagerIndex.js
@@ -8,6 +8,12 @@ import FilterableDataTable from 'FilterableDataTable';
import InstrumentUploadForm from './uploadForm';
+import Modal from 'jsx/Modal';
+import InfoPanel from 'jsx/InfoPanel';
+
+import Select from 'react-select';
+import swal from 'sweetalert2';
+
/**
* Instrument Manager Index component
*/
@@ -23,6 +29,7 @@ class InstrumentManagerIndex extends Component {
data: {},
error: false,
isLoaded: false,
+ modifyPermissions: false,
};
this.fetchData = this.fetchData.bind(this);
@@ -62,6 +69,40 @@ class InstrumentManagerIndex extends Component {
* @return {*} a formated table cell for a given column
*/
formatColumn(column, cell, row) {
+ if (column == 'Permission Required') {
+ const clickHandler = (row) => {
+ return () => {
+ this.setState({
+ 'modifyPermissions': {
+ 'instrument': row.Instrument,
+ 'permissions': row['Permission Required'],
+ },
+ });
+ };
+ };
+ if (cell == null) {
+ if (this.props.hasPermission('instrument_manager_write')) {
+ return (
No Permissions enforced.
+
+ | );
+ } else {
+ return No Permissions enforced. | ;
+ }
+ }
+ if (this.props.hasPermission('instrument_manager_write')) {
+ return ({cell.join(',')}
+
+ | );
+ } else {
+ return {cell.join(',')} | ;
+ }
+ }
return (
{cell} |
);
@@ -114,12 +155,82 @@ class InstrumentManagerIndex extends Component {
name: 'pagesValid',
type: 'text',
}},
+ {label: 'Permission Required', show: true, filter: {
+ name: 'permissionsRequired',
+ type: 'text',
+ }},
];
const tabs = [
{id: 'browse', label: 'Browse'},
];
+ let permsModal = null;
+ if (this.state.modifyPermissions !== false) {
+ const submitPromise = () => {
+ return new Promise(
+ (resolve, reject) => {
+ fetch(
+ this.props.BaseURL + '/instrument_manager/permissions',
+ {
+ method: 'POST',
+ body: JSON.stringify(this.state.modifyPermissions),
+ }).then((response) => {
+ if (!response.ok) {
+ console.error(response.status);
+ throw new Error('Could not modify permissions');
+ }
+ return response.json();
+ }).then( (data) => {
+ resolve();
+ this.fetchData();
+ }).catch((message) => {
+ swal.fire({
+ title: 'Oops..',
+ text: 'Something went wrong!',
+ type: 'error',
+ });
+ reject();
+ });
+ });
+ };
+
+ permsModal = ( {
+ this.setState({'modifyPermissions': false});
+ }
+ }>
+ Select the permissions required for accessing
+ {this.state.modifyPermissions.instrument} in the dropdown below.
+
+ Any user accessing the instrument (either for viewing the data
+ or data entry) must have one of the access permissions selected.
+
+
+ A user with any of the selected permissions will
+ be able to access
+ {this.state.modifyPermissions.instrument}.
+ If no permissions are selected, the default LORIS permissions
+ will be enforced for this instrument.
+
+
+ {
+ let modifyPermissions = {...this.state.modifyPermissions};
+ modifyPermissions.permissions = newselected;
+ this.setState({modifyPermissions});
+ }}
+ />
+ );
+ }
if (this.props.hasPermission('instrument_manager_write')) {
tabs.push({id: 'upload', label: 'Upload'});
}
@@ -165,6 +276,7 @@ class InstrumentManagerIndex extends Component {
return (
+ {permsModal}
{
+ return {value: val, label: val};
+ });
+ const values = options.filter((row) => {
+ if (props.selected == null) {
+ // nothing selected, filter everything
+ return false;
+ }
+ return props.selected.includes(row.value);
+ });
+ return