-
Notifications
You must be signed in to change notification settings - Fork 192
[Candidate_parameters, Core] Normalizing Consent in LORIS #3504
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…_normalise_consent
| foreach ($consents as $key=>$consent) { | ||
| // Do consent columns exist in old table? | ||
| $consentName = $consent['name']; | ||
| $columnQuery = 'SHOW COLUMNS FROM participant_status LIKE "' . $consentName . '"'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ridz1208 at the moment, only the columns with status information is being checked for existence in participant_status. do you think this is enough or should we also be checking for the existence of the _date and _withdrawal columns too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the check shouldbe done on all columns since you dont want to assume that they exist... just to be sure.
| // Do consent columns exist in old table? | ||
| $consentName = $consent['name']; | ||
| $columnQuery = 'SHOW COLUMNS FROM participant_status LIKE "' . $consentName . '"'; | ||
| $columnExists = $db->pselect($columnQuery, array()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might wan to use the database column exist function !!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ahh!! okay
| CREATE TABLE `candidate_consent_type_history` ( | ||
| `CandidateConsentHistoryID` int(10) unsigned NOT NULL AUTO_INCREMENT, | ||
| `PSCID` varchar(255) NOT NULL, | ||
| `ConsentName` varchar(255) NOT NULL, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be a foreign key on consent_type. right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@xlecours similar to the old consent_info_history table, this table should only be a log of data submitted on the front-end, unaffected by changes in data of the other consent tables, but with more meaningful fields for users reading the history on the front-end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. The primary goal of this PR is to remove the consent from config.xml and not to redesign the way we log events.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@xlecours a secondary goal, which I think is just as important, is to implement the new SQL modelling standard, hence the renovation of the existing consent history table
| `CandidateID` int(6) NOT NULL, | ||
| `ConsentTypeID` int(2) NOT NULL, | ||
| `Status` enum('yes', 'no', 'not_answered') NOT NULL, | ||
| `DateGiven` date DEFAULT NULL, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as per https://github.com/aces/Loris/blob/19.0-dev/docs/SQLModelingStandard.md (Which should be propagated to minor),
ENUM are not permitted.
Could use this occasion to add a table "option" with "TableName", "AttributeName", "Value" attributes. This would create the table to replace all ENUM within the DB. Don't forget the (artificial) primary key.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Im not sure about this design... I actually told zaliqa to keep it as an enum until we discuss how to tackle it.
Sever places will use the yes/no options in loris and im not sure if those options should also include "not answered" or other options.
Id like to bring this up at the loris meeting so it can be discussed with everyone
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yepp, let's put it through as enum for now until a standard for all options in the database is decided on
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent idea, we could create a class for that so it be easy on projects to use the feature. I should work on that after I'm finish with visit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the reason for yes/no enums in LORIS is that MySQL mutilates "boolean" to tinyint(1) and changes true/false to 1/0.
Maybe we should document that and update the SQL standards? (not answered doesn't make sense though)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah i agree, i wanted to talk about the not answered option at tomorrow's meeting
| CONSTRAINT `PK_candidate_consent_type_rel` PRIMARY KEY (`CandidateID`,`ConsentTypeID`), | ||
| CONSTRAINT `FK_candidate_consent_type_rel_CandidateID` FOREIGN KEY (`CandidateID`) REFERENCES `candidate` (`CandID`), | ||
| CONSTRAINT `FK_candidate_consent_type_rel_ConsentTypeID` FOREIGN KEY (`ConsentTypeID`) REFERENCES `consent_type` (`ConsentTypeID`) | ||
| ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FK should containt "on cascade" and "on delete" clause
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PapillonMcGill did you mean "on update" and "on delete"? i dont think there's an "on cascade"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@zaliqarosli i would assume so, and on that note, you should update the delete_candidate php script to delete the fields from the tables you added
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@zaliqarosli yes, on delete and on update. Look like I write faster than I think. Must be in need of vacation ;-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| `DateWithdrawn` date DEFAULT NULL, | ||
| `EntryStaff` varchar(255) DEFAULT NULL, | ||
| `EntryDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||
| CONSTRAINT `PK_candidate_consent_type_history` PRIMARY KEY (`CandidateConsentHistoryID`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
varchar() should be after date and timestamp field.
no ENUM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you explain why the varchar comes after the date and timestamp?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@zaliqarosli For efficiency, if DB engine want to read a field placed after, it as to traverse the varchar() until the end. Can't jump directly to the required field start as the offset from row start in not fixed.
I'm preparing a presentation on that for an ADM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ahh okay i think i know what you mean. looking forward to the adm!
| static function getConsentList() | ||
| { | ||
| $DB =& Database::singleton(); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be
$factory = NDB_Factory::singleton();
$db = $factory->database();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PapillonMcGill could you explain this to me please? I've seen both used and not sure what the difference is
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PapillonMcGill i do see that the other functions in Utility follow the way you mentioned
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@zaliqarosli For more info, should ask @xlecours. I saw that he made a PR #3507 for that. I just wanted to do all uniformly.
Suspect it as to do with uniformity to simplify testing
| $fieldsInQuery = "SELECT c.DoB, | ||
| c.CandID, | ||
| c.CandID, | ||
| c.PSCID, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extra space!
| c.CandID, | ||
| c.DoB, | ||
| c.CandID, | ||
| c.PSCID, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extra space at end of line 147
missing space at line 148
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PapillonMcGill thanks for your review! will make these changes :)
| `EntryDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||
| `EntryStaff` varchar(255) DEFAULT NULL, | ||
| CONSTRAINT `PK_candidate_consent_type_history` PRIMARY KEY (`CandidateConsentHistoryID`) | ||
| ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
still some varchar() before date and timestamp,
Nullable should be after not null
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think i need more coffee
|
|
||
| CREATE TABLE `candidate_consent_type_history` ( | ||
| `CandidateConsentHistoryID` int(10) unsigned NOT NULL AUTO_INCREMENT, | ||
| `EntryDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PapillonMcGill did i get it right this time? lol
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup!
php/libraries/Candidate.class.inc
Outdated
| $factory = NDB_Factory::singleton(); | ||
| $db = $factory->database(); | ||
|
|
||
| $query = "SELECT * |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please specify the columns.
- They are no all used
- If some get changed in the schema, it is not obvious that it was used here?
- If this need to join other tables, it will gather all those new table's columns
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agree
php/libraries/Utility.class.inc
Outdated
| { | ||
| $DB =& Database::singleton(); | ||
|
|
||
| $query = "SELECT * FROM consent_type"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please specify the columns.
| } else { | ||
| // Check for zero dates | ||
| $psData = $db->pselect( | ||
| 'SELECT * FROM participant_status WHERE ' . $consentName . ' IS NOT NULL OR ' . $consentName . ' != ""', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please specify the columns.
|
|
||
| // Get all data where the consent status has a value | ||
| $psData = $db->pselect( | ||
| 'SELECT * FROM participant_status WHERE ' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please specify the columns.
|
|
||
| // Select consent history and import into new history table | ||
| $consentHistory = $db->pselect( | ||
| 'SELECT * FROM consent_info_history', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please specify the columns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i already said I AGREE !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@xlecours thank you for your input!! i made the changes for all the other queries but for this one, the field names in the old history table are dynamically set by the consent types. I'll specify the predicted column names here but it'll be in a concatenated query
|
|
||
| array_push($commentHistory, $unformattedComments); | ||
| $historyData = $db->pselect( | ||
| "SELECT * |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please specify the columns.
| // Select consent history and import into new history table | ||
| $historyFieldsQuery = 'SELECT CandID, entry_staff, data_entry_date'; | ||
| foreach ($consentType as $consentName => $consentLabel) { | ||
| $historyFieldsQuery .= ', ' . $consentName . ', ' . $consentName . '_date, ' . $consentName . '_withdrawal'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@xlecours let me know what you think
driusan
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some preliminary review, but this is too big to review in one sitting. Can you try and split this up into multiple smaller self-contained PRs?
The schema+import script would make a good start for a first one without touching any other code.
| CREATE TABLE `candidate_consent_type_rel` ( | ||
| `CandidateID` int(6) NOT NULL, | ||
| `ConsentTypeID` int(2) NOT NULL, | ||
| `Status` enum('yes', 'no', 'not_answered') NOT NULL, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No enums in the core tables is the new rule. yes, no, not_answered NOT NULL also doesn't really make sense. It should just be yes, no, NULLABLE, and (at that point it's just a boolean, not an enum, which makes more sense)
| `PSCID` varchar(255) NOT NULL, | ||
| `ConsentName` varchar(255) NOT NULL, | ||
| `ConsentLabel` varchar(255) NOT NULL, | ||
| `Status` enum('yes','no','not_answered') NOT NULL, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to enum or not to enum appears to be a point of contention.. to be determined hopefully tomorrow
SQL/0000-00-00-schema.sql
Outdated
| `DateGiven` date DEFAULT NULL, | ||
| `DateWithdrawn` date DEFAULT NULL, | ||
| `EntryStaff` varchar(255) DEFAULT NULL, | ||
| `EntryDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The history should never be updated, why does this have an ON UPDATE clause?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as suggested by @PapillonMcGill and the new SQL modelling standard
| INSERT INTO ConfigSettings (Name, Description, Visible, AllowMultiple, DataType, Parent, Label, OrderNumber) SELECT 'allowPrenatalTimepoints', 'Determines whether creation of timepoints prior to Date of Birth is allowed', 1, 0, 'boolean', ID, 'Allow Prenatal Timepoints', 21 FROM ConfigSettings WHERE Name="study"; | ||
| INSERT INTO ConfigSettings (Name, Description, Visible, AllowMultiple, DataType, Parent, Label, OrderNumber) SELECT 'ImagingUploaderAutoLaunch', "Allows running the ImagingUpload pre-processing scripts", 1, 0, 'boolean', ID, 'ImagingUploader Auto Launch',22 FROM ConfigSettings WHERE Name="study"; | ||
| INSERT INTO ConfigSettings (Name, Description, Visible, AllowMultiple, DataType, Parent, Label, OrderNumber) SELECT 'citation_policy', 'Citation Policy for Acknowledgements module', 1, 0, 'textarea', ID, 'Citation Policy', 23 FROM ConfigSettings WHERE Name="study"; | ||
| INSERT INTO ConfigSettings (Name, Description, Visible, AllowMultiple, DataType, Parent, Label, OrderNumber) SELECT 'CSPAdditionalHeaders', 'Extensions to the Content-security policy allow only for self-hosted content', 1, 0, 'text', ID, 'Content-Security Extensions', 24 FROM ConfigSettings WHERE Name="study"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is all this changed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ridz1208 wanted to update the order of the statements
| $consentDetails = Utility::getConsentList(); | ||
|
|
||
| // Get list of consents for candidate | ||
| $candidateConsent = Candidate::getConsent($candID); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't (and shouldn't be) defined as a static function below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what do you mean? could you be more explicit please?
| * @return array List of consents and their associated values for this candidate. | ||
| * The keys of the arrays are the IDs of the consents | ||
| */ | ||
| function getConsent($candID) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't make sense for any functions in the Candidate class to take a candID as a parameter. It's the candidate class, it already knows what it's candID is.
This should probably have a consent type parameter instead though, shouldn't it?
php/libraries/Candidate.class.inc
Outdated
| $factory = NDB_Factory::singleton(); | ||
| $db = $factory->database(); | ||
|
|
||
| $query = "SELECT * |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Select * should be avoided in favour of explicit column names, otherwise the code is going to be brittle with schema changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh yes, @xlecours pointed that out for other statements, i missed these ones
php/libraries/Utility.class.inc
Outdated
| { | ||
| $DB =& Database::singleton(); | ||
|
|
||
| $query = "SELECT * FROM consent_type"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment, avoid SELECT *
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@driusan cool, thanks for all your comments. i'll make the changes and work on sending out smaller, more contained PRs
| foreach ($result as $row) { | ||
| $list[$row["ConsentTypeID"]] = $row; | ||
| unset($list[$row["ConsentTypeID"]]["ConsentTypeID"]); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't @ridz1208 recently add a variant of pselect to make this easier?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ridz1208 is he talking about pselectCol? i forgot what the above foreach statement does
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think pselectcolwithindex something
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's a reference to the PR #3428 - The function is called 'pselectWithIndexKey()'
| `CandidateID` int(6) NOT NULL, | ||
| `ConsentTypeID` int(2) NOT NULL, | ||
| `Status` enum('yes', 'no', 'not_answered') NOT NULL, | ||
| `DateGiven` date DEFAULT NULL, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the reason for yes/no enums in LORIS is that MySQL mutilates "boolean" to tinyint(1) and changes true/false to 1/0.
Maybe we should document that and update the SQL standards? (not answered doesn't make sense though)
| `ConsentTypeID` int(2) NOT NULL AUTO_INCREMENT, | ||
| `Name` varchar(255) NOT NULL, | ||
| `Label` varchar(255) NOT NULL, | ||
| CONSTRAINT `PK_consent_type` PRIMARY KEY (`ConsentTypeID`), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do these 2 varchar() field need 255 chars?
What is the practical / forecast max length for the name and label?
Would 15 or 20 for Name and 20 or 30 for Label be sufficient?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New PR #3532 if you could redirect reviews there
| c.DoB, | ||
| c.CandID, | ||
| c.DoB, | ||
| c.CandID, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extra space at end of line
This PR transforms the current implementation of consent into a normalized structure. Current behaviour on the front-end shouldn't be affected.
Changes targeted:
Discussions required:
Moving forward:
The ajax scripts are a little hacky in order to be compatible with changes in the back-end while keeping the front-end untouched. The next step would be to clean up how consent is used in the front-end and fix up the ajax scripts in parallel.
See also: #3263, #3315, #3348
How to test:
Import_Data_Normalise_Consent.php- check new tables are populated when successfulparticipant_statusandconsent_info_historyand drop deprecated columns/tables in DB as instructed by above scriptCouchDB_Import_Demographics.php