From 01a551f92fe3a073ecd97e048bf29e4ede7cd5a5 Mon Sep 17 00:00:00 2001
From: devincowan
Date: Mon, 5 Oct 2020 11:24:18 -0600
Subject: [PATCH 1/8] add JSON file export start work on JSON file import
---
DataQualityExternalModule.php | 307 ++++++++++++++++++++++++++++++++-
config.json | 15 +-
exportJsonFile.php | 136 +++++++++++++++
importJsonFile.php | 316 ++++++++++++++++++++++++++++++++++
index.php | 39 +++++
5 files changed, 810 insertions(+), 3 deletions(-)
create mode 100644 exportJsonFile.php
create mode 100644 importJsonFile.php
create mode 100644 index.php
diff --git a/DataQualityExternalModule.php b/DataQualityExternalModule.php
index b8d0f32..61d81ba 100644
--- a/DataQualityExternalModule.php
+++ b/DataQualityExternalModule.php
@@ -15,4 +15,309 @@ public function checkApiToken() {
$post = $data->getRequestVars();
}
-}
\ No newline at end of file
+
+ public function getProcessJsonDownURL() {
+ return $this->getUrl("exportJsonFile.php", false, false);
+ }
+
+ public function getProcessJsonUpURL() {
+ return $this->getUrl("importJsonFile.php", false, false);
+ }
+
+ public function import_json_file() {
+ global $format, $returnFormat, $post;
+
+ // Get user's user rights
+ $user_rights = UserRights::getPrivileges(PROJECT_ID, USERID);
+ $user_rights = $user_rights[PROJECT_ID][strtolower(USERID)];
+ $ur = new UserRights();
+ $ur->setFormLevelPrivileges();
+
+ $Proj = new Project(PROJECT_ID);
+ $errors = array();
+
+ // Prevent data imports for projects in inactive or archived status
+ if ($Proj->project['status'] > 1) {
+ if ($Proj->project['status'] == '2') {
+ $statusLabel = "Inactive";
+ } elseif ($Proj->project['status'] == '3') {
+ $statusLabel = "Archived";
+ } else {
+ $statusLabel = "[unknown]";
+ }
+ array_push($errors, "Data may not be imported because the project is in $statusLabel status.");
+ }
+
+ $insertValues = [];
+ $resolutionInsertIds = [];
+ $userIdConversion = array(NULL => NULL);
+
+ $projectSettings = $Proj->project;
+ $dataQualityProcess = false;
+ $dataCommentProcess = false;
+ $editComments = false;
+
+ ## Check if project has data resolution workflow turned on and ability to delete data resolution comments
+ if($projectSettings['data_resolution_enabled'] == 2) {
+ $dataQualityProcess = true;
+ }
+ else if($projectSettings['data_resolution_enabled'] == 1) {
+ $dataCommentProcess = true;
+ }
+ else {
+ array_push($errors, "Data may not be imported because the project does not have data quality enabled."));
+ }
+
+ if($projectSettings['field_comment_edit_delete'] == 1) {
+ $editComments = true;
+ }
+
+ $single_event = false;
+ if(sizeof($Proj->events)==1 && $projectSettings['repeatforms']==0){
+ $single_event = true;
+ }
+
+ ## TODO Convert flat/csv data into nested array format
+ $importData = json_decode($post['import_file'],true);
+
+ foreach($importData as $dataRow) {
+ $statusId = $dataRow['status_id'];
+ $record = $dataRow['record'];
+ $projectId = $dataRow['project_id'];
+ $eventId = $dataRow['event_id'];
+ $fieldName = $dataRow['field_name'];
+ $instance = $dataRow['instance'];
+ $repeatInstrument = $dataRow['repeat_instrument'];
+ $assignedUsername = $dataRow['assigned_username'];
+ $newStatusId = false;
+
+ ## Verify field name and event ID exist on this project. Skip this row if it doesn't
+ if(!array_key_exists($fieldName,$Proj->metadata)) {
+ continue;
+ }
+
+ $eventFound = false;
+ foreach($Proj->events as $armDetails) {
+ foreach($armDetails["events"] as $tempEventId => $eventDetails) {
+ // check for non-longitudinal project
+ if (count($armDetails['events']) == 1 && $single_event){
+ $eventId = $tempEventId;
+ $eventFound = true;
+ break 2;
+ }else if($eventId == $tempEventId) {
+ $eventFound = true;
+ break 2;
+ }
+ }
+ }
+
+ if(!$eventFound) {
+ continue;
+ }
+
+ ## Skip if record/project/event/field is blank
+ if($record == "" || $projectId == "" || $eventId == "" || $fieldName == "") continue;
+
+ ## Skip data where the projectId doesn't match the token's projectId
+ if($projectId != PROJECT_ID) continue;
+
+
+ ## Confirm if this status is already in the database
+ $sql = "SELECT s.status_id, s.instance, s.repeat_instrument, s.record, s.project_id, s.event_id, s.field_name
+ FROM redcap_data_quality_status s
+ WHERE ".(($statusId == "" || !is_numeric($statusId)) ? "" : "s.status_id = '".db_escape($statusId)."'")."
+ OR (s.record = '".db_escape($record)."'
+ AND s.project_id = '".db_escape($projectId)."'
+ AND s.event_id = '".db_escape($eventId)."'
+ AND s.field_name = '".db_escape($fieldName)."'".
+ ($repeatInstrument != NULL ? " AND s.repeat_instrument = '".db_escape($repeatInstrument)."'" :
+ ($instance == NULL ? " AND s.instance is NULL" : " AND s.instance = '".db_escape($instance)."'")).")";
+
+ $q = db_query($sql);
+
+ ## Cache User ID to username conversion to reduce DB calls
+ if(!array_key_exists($assignedUsername,$userIdConversion)) {
+ $userIdConversion[$assignedUsername] = User::getUIIDByUsername($assignedUsername);
+ }
+
+ $existingStatus = "";
+ while($row = db_fetch_assoc($q)) {
+ ## Found a matching record/project/event/field/instance with a different status
+ if($row['status_id'] != $statusId) {
+ $existingStatus = $row['status_id'];
+ $newStatusId = true;
+ }
+ ## Found a row for that statusId, verify if record/project/event/field/instance matches
+ else if($row['record'] == $record && $row['project_id'] == $projectId
+ && $row['event_id'] == $eventId && $row['field_name'] == $fieldName){
+ if($instance == "" || $row['instance'] == $instance) {
+ $existingStatus = $row['status_id'];
+ $newStatusId = false;
+ }
+ }
+ }
+
+ ## Add new status row
+ if($existingStatus == "") {
+ $sql = "INSERT INTO redcap_data_quality_status
+ (non_rule,project_id,record,event_id,field_name,instance,assigned_user_id)
+ VALUES (1,".db_escape($projectId).",".db_escape($record).",".db_escape($eventId).",'".
+ db_escape($fieldName)."',".checkNull($instance).",".checkNull($userIdConversion[$assignedUsername]).")";
+
+ db_query($sql);
+ $existingStatus = db_insert_id();
+ $newStatusId = true;
+ }
+
+ ## Do date conversion on resolutions so they can be quickly sorted
+ foreach($dataRow['resolutions'] as $resKey => $resolutionRow) {
+ $dataRow['resolutions'][$resKey]['tsInSeconds'] = strtotime($resolutionRow['ts']);
+ }
+
+ ## Sort resolutions by timestamp and get last timestamp in DB
+ usort($dataRow['resolutions'],function($a,$b) {
+ if($a['tsInSeconds'] > $b['tsInSeconds']) {
+ return 1;
+ }
+ else if($a['tsInSeconds'] == $b['tsInSeconds']) {
+ return 0;
+ }
+ return -1;
+ });
+
+ $sql = "SELECT r.ts,r.user_id
+ FROM redcap_data_quality_resolutions r
+ WHERE r.status_id = '".$existingStatus."'
+ ORDER BY r.ts DESC";
+
+ $q = db_query($sql);
+ $existingResolutions = array();
+ while($row = db_fetch_assoc($q)) {
+ $existingResolutions[$row['ts'].$row['user_id']] = 1;
+ }
+
+ $dbTs = db_result($q,0,"ts");
+ $lastTs = "";
+
+ foreach($dataRow['resolutions'] as $resolutionRow) {
+ if($editComments) {
+ # TODO Allow update of data resolution status/comments
+ //DataQuality::editFieldComment();
+ }
+
+ // Determine the status to set
+ if (in_array($resolutionRow['current_query_status'], array('OPEN','CLOSED','VERIFIED','DEVERIFIED'))) {
+ $resStatus = $resolutionRow['current_query_status'];
+ } elseif ((isset($resolutionRow['response_requested']) && $resolutionRow['response_requested'])
+ || ($resolutionRow['response'] && $resolutionRow['response'])) {
+ $resStatus = 'OPEN';
+ } else {
+ $resStatus = '';
+ }
+
+ // Make sure response is in enum list
+ if(in_array($resolutionRow['response'],array('DATA_MISSING','TYPOGRAPHICAL_ERROR','CONFIRMED_CORRECT','WRONG_SOURCE','OTHER'))) {
+ $response = $resolutionRow['response'];
+ }
+ else {
+ $response = '';
+ }
+
+ $resolutionId = $resolutionRow['res_id'];
+ $resStatusId = $resolutionRow['status_id'];
+ $username = $resolutionRow['username'];
+
+ ## Skip resolution rows that don't have matching status IDs unless this is a new status
+ if(!$newStatusId && $resStatusId != "" && $resStatusId != $existingStatus) continue;
+
+ ## Cache User ID to username conversion to reduce DB calls
+ if(!array_key_exists($username,$userIdConversion)) {
+ $userIdConversion[$username] = User::getUIIDByUsername($username);
+ }
+
+ ## Skip resolution rows that already have a resolution from the same user for the same timestamp
+ ## This is to prevent duplicate response rows
+ if(array_key_exists($resolutionRow['ts'].$userIdConversion[$username],$existingResolutions)) {
+ continue;
+ }
+
+ $lastTs = $resolutionRow['ts'];
+
+ $insertValues[] = "(".checkNull($existingStatus).",".checkNull($resolutionRow['ts']).",".
+ checkNull($userIdConversion[$username]).",".(in_array($resolutionRow['response_requested'],[0,1]) ? $resolutionRow['response_requested'] : 0).",".
+ checkNull($response).",".checkNull($resolutionRow['comment']).",".
+ checkNull($resStatus).")";
+
+ $existingResolutions[$resolutionRow['ts'].$userIdConversion[$username]] = 1;
+
+ ## Do inserts in groups of 10 to reduce DB calls
+ if(count($insertValues) >= 10) {
+ $sql = "INSERT INTO redcap_data_quality_resolutions
+ (status_id,ts,user_id,response_requested,response,comment,current_query_status)
+ VALUES ".implode(",",$insertValues);
+ db_query($sql);
+
+ if($e = db_error()) {
+ error_log("Data Quality Import: ".$e);
+ }
+ else {
+ $nextId = db_insert_id();
+ for($i = 0; $i < 10; $i++) {
+ $resolutionInsertIds[] = $nextId + $i;
+ }
+ }
+ $insertValues = [];
+ }
+ }
+
+ ## If last timestamp is after last timestamp in DB, then update main query_status
+ if($existingStatus && $lastTs != "" && strtotime($lastTs) > strtotime($dbTs)) {
+ $sql = "UPDATE redcap_data_quality_status
+ SET query_status = ".checkNull($resStatus)."
+ WHERE status_id = ".$existingStatus;
+
+ db_query($sql);
+ }
+ }
+
+ if(count($insertValues) > 0) {
+ ## Do last inserts pending in $insertValues
+ $sql = "INSERT INTO redcap_data_quality_resolutions
+ (status_id,ts,user_id,response_requested,response,comment,current_query_status)
+ VALUES ".implode(",",$insertValues);
+ db_query($sql);
+
+ if($e = db_error()) {
+ error_log("Data Quality Import: ".$e);
+ }
+ else {
+ $nextId = db_insert_id();
+ for($i = 0; $i < count($insertValues); $i++) {
+ $resolutionInsertIds[] = $nextId + $i;
+ }
+ }
+ $insertValues = [];
+ }
+
+ ## TODO Send other types of responses based on request
+ $content = json_encode($resolutionInsertIds);
+ return ($errors);
+
+ function csv($data,$headers) {
+ foreach($data as $dataRow) {
+ foreach($headers as $column => $label) {
+ if($label == "record") {
+ ## If record is blank, this must be a data resolution row
+ if($dataRow[$column] == "") {
+
+ }
+ ## Else, this must be a status row
+ else {
+
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/config.json b/config.json
index 4f095e8..98eb482 100644
--- a/config.json
+++ b/config.json
@@ -12,12 +12,23 @@
"institution": "Vanderbilt University Medical Center"
}
],
-
+
"permissions": [
],
"no-auth-pages":["import","export"],
"project-settings": [
- ]
+ ],
+
+ "links": {
+ "project": [
+ {
+ "name": "Export/Import DRW JSON",
+ "icon": "arrow_circle_double_135",
+ "url": "index.php",
+ "show-header-and-footer": true
+ }
+ ]
+ }
}
diff --git a/exportJsonFile.php b/exportJsonFile.php
new file mode 100644
index 0000000..1dcc08e
--- /dev/null
+++ b/exportJsonFile.php
@@ -0,0 +1,136 @@
+ NULL);
+
+## Read all the rows from the table ino the $statusList variable
+while($row = db_fetch_assoc($q)) {
+ $userId = $row['assigned_user_id'];
+ unset($row['assigned_user_id']);
+
+ ## Cache User ID to username conversion to reduce DB calls
+ if(!array_key_exists($userId,$userIdConversion)) {
+ $userIdConversion[$userId] = User::getUserInfoByUiid($userId)['username'];
+ }
+ $row['assigned_username'] = $userIdConversion[$userId];
+ $statusList[$row['status_id']] = $row;
+}
+
+if(count($statusList) > 0) {
+ $sql = "SELECT r.*
+ FROM redcap_data_quality_resolutions r
+ WHERE r.status_id IN ('".implode("','",array_keys($statusList))."')";
+
+ $q = db_query($sql);
+
+ if($e = db_error()) {
+ throw new Exception("Database error while pulling data quality resolutions");
+ }
+
+ while($row = db_fetch_assoc($q)) {
+ if(!array_key_exists("resolutions",$statusList[$row['status_id']])) {
+ $statusList[$row['status_id']]["resolutions"] = array();
+ }
+ $userId = $row['user_id'];
+ unset($row['user_id']);
+
+ ## Cache User ID to username conversion to reduce DB calls
+ if(!array_key_exists($userId,$userIdConversion)) {
+ $userIdConversion[$userId] = User::getUserInfoByUiid($userId)['username'];
+ }
+ $row['username'] = $userIdConversion[$userId];
+ $statusList[$row['status_id']]["resolutions"][$row["res_id"]] = $row;
+ }
+}
+
+// $uid = User::getUIIDByUsername($post['user']);
+
+// $retData = array(
+// 'uid' => $uid,
+// 'user' => $post['user'],
+// 'sql' => $sql
+// );
+
+// $content = json_encode($sql1);
+$content = json_encode($statusList);
+
+# Export to a JSON file
+$datestamp = new DateTime();
+$filename=$project_id."-data_quality-".$datestamp->format("Y-m-d").".json";
+
+// $fp = fopen($filename, 'w');
+// fwrite($fp, $content);
+// fclose($fp);
+
+header("Content-type: application/json");
+header("Content-Disposition: attachment; filename=".$filename);
+header("Pragma: no-cache");
+header("Expires: 0");
+
+echo($content);
diff --git a/importJsonFile.php b/importJsonFile.php
new file mode 100644
index 0000000..01366c1
--- /dev/null
+++ b/importJsonFile.php
@@ -0,0 +1,316 @@
+setFormLevelPrivileges();
+
+$Proj = new Project(PROJECT_ID);
+$errors = array();
+
+// Prevent data imports for projects in inactive or archived status
+if ($Proj->project['status'] > 1) {
+ if ($Proj->project['status'] == '2') {
+ $statusLabel = "Inactive";
+ } elseif ($Proj->project['status'] == '3') {
+ $statusLabel = "Archived";
+ } else {
+ $statusLabel = "[unknown]";
+ }
+ array_push($errors, "Data may not be imported because the project is in $statusLabel status.");
+}
+
+$insertValues = [];
+$resolutionInsertIds = [];
+$userIdConversion = array(NULL => NULL);
+
+$projectSettings = $Proj->project;
+$dataQualityProcess = false;
+$dataCommentProcess = false;
+$editComments = false;
+
+## Check if project has data resolution workflow turned on and ability to delete data resolution comments
+if($projectSettings['data_resolution_enabled'] == 2) {
+ $dataQualityProcess = true;
+}
+else if($projectSettings['data_resolution_enabled'] == 1) {
+ $dataCommentProcess = true;
+}
+else {
+ array_push($errors, "Data may not be imported because the project does not have data quality enabled."));
+}
+
+if($projectSettings['field_comment_edit_delete'] == 1) {
+ $editComments = true;
+}
+
+$single_event = false;
+if(sizeof($Proj->events)==1 && $projectSettings['repeatforms']==0){
+ $single_event = true;
+}
+
+## TODO Convert flat/csv data into nested array format
+$importData = json_decode($post['import_file'],true);
+
+foreach($importData as $dataRow) {
+ $statusId = $dataRow['status_id'];
+ $record = $dataRow['record'];
+ $projectId = $dataRow['project_id'];
+ $eventId = $dataRow['event_id'];
+ $fieldName = $dataRow['field_name'];
+ $instance = $dataRow['instance'];
+ $repeatInstrument = $dataRow['repeat_instrument'];
+ $assignedUsername = $dataRow['assigned_username'];
+ $newStatusId = false;
+
+ ## Verify field name and event ID exist on this project. Skip this row if it doesn't
+ if(!array_key_exists($fieldName,$Proj->metadata)) {
+ continue;
+ }
+
+ $eventFound = false;
+ foreach($Proj->events as $armDetails) {
+ foreach($armDetails["events"] as $tempEventId => $eventDetails) {
+ // check for non-longitudinal project
+ if (count($armDetails['events']) == 1 && $single_event){
+ $eventId = $tempEventId;
+ $eventFound = true;
+ break 2;
+ }else if($eventId == $tempEventId) {
+ $eventFound = true;
+ break 2;
+ }
+ }
+ }
+
+ if(!$eventFound) {
+ continue;
+ }
+
+ ## Skip if record/project/event/field is blank
+ if($record == "" || $projectId == "" || $eventId == "" || $fieldName == "") continue;
+
+ ## Skip data where the projectId doesn't match the token's projectId
+ if($projectId != PROJECT_ID) continue;
+
+
+ ## Confirm if this status is already in the database
+ $sql = "SELECT s.status_id, s.instance, s.repeat_instrument, s.record, s.project_id, s.event_id, s.field_name
+ FROM redcap_data_quality_status s
+ WHERE ".(($statusId == "" || !is_numeric($statusId)) ? "" : "s.status_id = '".db_escape($statusId)."'")."
+ OR (s.record = '".db_escape($record)."'
+ AND s.project_id = '".db_escape($projectId)."'
+ AND s.event_id = '".db_escape($eventId)."'
+ AND s.field_name = '".db_escape($fieldName)."'".
+ ($repeatInstrument != NULL ? " AND s.repeat_instrument = '".db_escape($repeatInstrument)."'" :
+ ($instance == NULL ? " AND s.instance is NULL" : " AND s.instance = '".db_escape($instance)."'")).")";
+
+ $q = db_query($sql);
+
+ ## Cache User ID to username conversion to reduce DB calls
+ if(!array_key_exists($assignedUsername,$userIdConversion)) {
+ $userIdConversion[$assignedUsername] = User::getUIIDByUsername($assignedUsername);
+ }
+
+ $existingStatus = "";
+ while($row = db_fetch_assoc($q)) {
+ ## Found a matching record/project/event/field/instance with a different status
+ if($row['status_id'] != $statusId) {
+ $existingStatus = $row['status_id'];
+ $newStatusId = true;
+ }
+ ## Found a row for that statusId, verify if record/project/event/field/instance matches
+ else if($row['record'] == $record && $row['project_id'] == $projectId
+ && $row['event_id'] == $eventId && $row['field_name'] == $fieldName){
+ if($instance == "" || $row['instance'] == $instance) {
+ $existingStatus = $row['status_id'];
+ $newStatusId = false;
+ }
+ }
+ }
+
+ ## Add new status row
+ if($existingStatus == "") {
+ $sql = "INSERT INTO redcap_data_quality_status
+ (non_rule,project_id,record,event_id,field_name,instance,assigned_user_id)
+ VALUES (1,".db_escape($projectId).",".db_escape($record).",".db_escape($eventId).",'".
+ db_escape($fieldName)."',".checkNull($instance).",".checkNull($userIdConversion[$assignedUsername]).")";
+
+ db_query($sql);
+ $existingStatus = db_insert_id();
+ $newStatusId = true;
+ }
+
+ ## Do date conversion on resolutions so they can be quickly sorted
+ foreach($dataRow['resolutions'] as $resKey => $resolutionRow) {
+ $dataRow['resolutions'][$resKey]['tsInSeconds'] = strtotime($resolutionRow['ts']);
+ }
+
+ ## Sort resolutions by timestamp and get last timestamp in DB
+ usort($dataRow['resolutions'],function($a,$b) {
+ if($a['tsInSeconds'] > $b['tsInSeconds']) {
+ return 1;
+ }
+ else if($a['tsInSeconds'] == $b['tsInSeconds']) {
+ return 0;
+ }
+ return -1;
+ });
+
+ $sql = "SELECT r.ts,r.user_id
+ FROM redcap_data_quality_resolutions r
+ WHERE r.status_id = '".$existingStatus."'
+ ORDER BY r.ts DESC";
+
+ $q = db_query($sql);
+ $existingResolutions = array();
+ while($row = db_fetch_assoc($q)) {
+ $existingResolutions[$row['ts'].$row['user_id']] = 1;
+ }
+
+ $dbTs = db_result($q,0,"ts");
+ $lastTs = "";
+
+ foreach($dataRow['resolutions'] as $resolutionRow) {
+ if($editComments) {
+ # TODO Allow update of data resolution status/comments
+ //DataQuality::editFieldComment();
+ }
+
+ // Determine the status to set
+ if (in_array($resolutionRow['current_query_status'], array('OPEN','CLOSED','VERIFIED','DEVERIFIED'))) {
+ $resStatus = $resolutionRow['current_query_status'];
+ } elseif ((isset($resolutionRow['response_requested']) && $resolutionRow['response_requested'])
+ || ($resolutionRow['response'] && $resolutionRow['response'])) {
+ $resStatus = 'OPEN';
+ } else {
+ $resStatus = '';
+ }
+
+ // Make sure response is in enum list
+ if(in_array($resolutionRow['response'],array('DATA_MISSING','TYPOGRAPHICAL_ERROR','CONFIRMED_CORRECT','WRONG_SOURCE','OTHER'))) {
+ $response = $resolutionRow['response'];
+ }
+ else {
+ $response = '';
+ }
+
+ $resolutionId = $resolutionRow['res_id'];
+ $resStatusId = $resolutionRow['status_id'];
+ $username = $resolutionRow['username'];
+
+ ## Skip resolution rows that don't have matching status IDs unless this is a new status
+ if(!$newStatusId && $resStatusId != "" && $resStatusId != $existingStatus) continue;
+
+ ## Cache User ID to username conversion to reduce DB calls
+ if(!array_key_exists($username,$userIdConversion)) {
+ $userIdConversion[$username] = User::getUIIDByUsername($username);
+ }
+
+ ## Skip resolution rows that already have a resolution from the same user for the same timestamp
+ ## This is to prevent duplicate response rows
+ if(array_key_exists($resolutionRow['ts'].$userIdConversion[$username],$existingResolutions)) {
+ continue;
+ }
+
+ $lastTs = $resolutionRow['ts'];
+
+ $insertValues[] = "(".checkNull($existingStatus).",".checkNull($resolutionRow['ts']).",".
+ checkNull($userIdConversion[$username]).",".(in_array($resolutionRow['response_requested'],[0,1]) ? $resolutionRow['response_requested'] : 0).",".
+ checkNull($response).",".checkNull($resolutionRow['comment']).",".
+ checkNull($resStatus).")";
+
+ $existingResolutions[$resolutionRow['ts'].$userIdConversion[$username]] = 1;
+
+ ## Do inserts in groups of 10 to reduce DB calls
+ if(count($insertValues) >= 10) {
+ $sql = "INSERT INTO redcap_data_quality_resolutions
+ (status_id,ts,user_id,response_requested,response,comment,current_query_status)
+ VALUES ".implode(",",$insertValues);
+ db_query($sql);
+
+ if($e = db_error()) {
+ error_log("Data Quality Import: ".$e);
+ }
+ else {
+ $nextId = db_insert_id();
+ for($i = 0; $i < 10; $i++) {
+ $resolutionInsertIds[] = $nextId + $i;
+ }
+ }
+ $insertValues = [];
+ }
+ }
+
+ ## If last timestamp is after last timestamp in DB, then update main query_status
+ if($existingStatus && $lastTs != "" && strtotime($lastTs) > strtotime($dbTs)) {
+ $sql = "UPDATE redcap_data_quality_status
+ SET query_status = ".checkNull($resStatus)."
+ WHERE status_id = ".$existingStatus;
+
+ db_query($sql);
+ }
+}
+
+if(count($insertValues) > 0) {
+ ## Do last inserts pending in $insertValues
+ $sql = "INSERT INTO redcap_data_quality_resolutions
+ (status_id,ts,user_id,response_requested,response,comment,current_query_status)
+ VALUES ".implode(",",$insertValues);
+ db_query($sql);
+
+ if($e = db_error()) {
+ error_log("Data Quality Import: ".$e);
+ }
+ else {
+ $nextId = db_insert_id();
+ for($i = 0; $i < count($insertValues); $i++) {
+ $resolutionInsertIds[] = $nextId + $i;
+ }
+ }
+ $insertValues = [];
+}
+
+## TODO Send other types of responses based on request
+$content = json_encode($resolutionInsertIds);
+
+# Send the response to the requestor
+// RestUtility::sendResponse(200, $content, $format);
+
+$dataQualityExternalModule = new \Vanderbilt\DataQualityExternalModule\DataQualityExternalModule();
+$errors = $dataQualityExternalModule->import_json_file();
+
+if (!empty($errors))
+{
+ require_once APP_PATH_DOCROOT . 'ProjectGeneral/header.php';
+ print "";
+ foreach($errors as $error)
+ {
+ print "
$error
";
+ }
+ print "
";
+ require_once APP_PATH_DOCROOT . 'ProjectGeneral/footer.php';
+}
+else
+{
+ header("Location: " . $dataQualityExternalModule->getUrl("index.php") . "&imported=1");
+}
+
+function csv($data,$headers) {
+ foreach($data as $dataRow) {
+ foreach($headers as $column => $label) {
+ if($label == "record") {
+ ## If record is blank, this must be a data resolution row
+ if($dataRow[$column] == "") {
+
+ }
+ ## Else, this must be a status row
+ else {
+
+ }
+ }
+ }
+ }
+}
diff --git a/index.php b/index.php
new file mode 100644
index 0000000..76a1938
--- /dev/null
+++ b/index.php
@@ -0,0 +1,39 @@
+
+
+ Export or Import Data Quality
+
+
+ Press download to export data resolution workflow data
+
+
+
+
+
+
+
+
+
+
Imported
+
+
+
+
+
+
+
+
+
Date: Mon, 5 Oct 2020 12:25:05 -0600
Subject: [PATCH 2/8] Import json files functioning
---
DataQualityExternalModule.php | 297 -------------------------
importJsonFile.php | 401 ++++++++++++++++++----------------
2 files changed, 208 insertions(+), 490 deletions(-)
diff --git a/DataQualityExternalModule.php b/DataQualityExternalModule.php
index 61d81ba..b8ca015 100644
--- a/DataQualityExternalModule.php
+++ b/DataQualityExternalModule.php
@@ -23,301 +23,4 @@ public function getProcessJsonDownURL() {
public function getProcessJsonUpURL() {
return $this->getUrl("importJsonFile.php", false, false);
}
-
- public function import_json_file() {
- global $format, $returnFormat, $post;
-
- // Get user's user rights
- $user_rights = UserRights::getPrivileges(PROJECT_ID, USERID);
- $user_rights = $user_rights[PROJECT_ID][strtolower(USERID)];
- $ur = new UserRights();
- $ur->setFormLevelPrivileges();
-
- $Proj = new Project(PROJECT_ID);
- $errors = array();
-
- // Prevent data imports for projects in inactive or archived status
- if ($Proj->project['status'] > 1) {
- if ($Proj->project['status'] == '2') {
- $statusLabel = "Inactive";
- } elseif ($Proj->project['status'] == '3') {
- $statusLabel = "Archived";
- } else {
- $statusLabel = "[unknown]";
- }
- array_push($errors, "Data may not be imported because the project is in $statusLabel status.");
- }
-
- $insertValues = [];
- $resolutionInsertIds = [];
- $userIdConversion = array(NULL => NULL);
-
- $projectSettings = $Proj->project;
- $dataQualityProcess = false;
- $dataCommentProcess = false;
- $editComments = false;
-
- ## Check if project has data resolution workflow turned on and ability to delete data resolution comments
- if($projectSettings['data_resolution_enabled'] == 2) {
- $dataQualityProcess = true;
- }
- else if($projectSettings['data_resolution_enabled'] == 1) {
- $dataCommentProcess = true;
- }
- else {
- array_push($errors, "Data may not be imported because the project does not have data quality enabled."));
- }
-
- if($projectSettings['field_comment_edit_delete'] == 1) {
- $editComments = true;
- }
-
- $single_event = false;
- if(sizeof($Proj->events)==1 && $projectSettings['repeatforms']==0){
- $single_event = true;
- }
-
- ## TODO Convert flat/csv data into nested array format
- $importData = json_decode($post['import_file'],true);
-
- foreach($importData as $dataRow) {
- $statusId = $dataRow['status_id'];
- $record = $dataRow['record'];
- $projectId = $dataRow['project_id'];
- $eventId = $dataRow['event_id'];
- $fieldName = $dataRow['field_name'];
- $instance = $dataRow['instance'];
- $repeatInstrument = $dataRow['repeat_instrument'];
- $assignedUsername = $dataRow['assigned_username'];
- $newStatusId = false;
-
- ## Verify field name and event ID exist on this project. Skip this row if it doesn't
- if(!array_key_exists($fieldName,$Proj->metadata)) {
- continue;
- }
-
- $eventFound = false;
- foreach($Proj->events as $armDetails) {
- foreach($armDetails["events"] as $tempEventId => $eventDetails) {
- // check for non-longitudinal project
- if (count($armDetails['events']) == 1 && $single_event){
- $eventId = $tempEventId;
- $eventFound = true;
- break 2;
- }else if($eventId == $tempEventId) {
- $eventFound = true;
- break 2;
- }
- }
- }
-
- if(!$eventFound) {
- continue;
- }
-
- ## Skip if record/project/event/field is blank
- if($record == "" || $projectId == "" || $eventId == "" || $fieldName == "") continue;
-
- ## Skip data where the projectId doesn't match the token's projectId
- if($projectId != PROJECT_ID) continue;
-
-
- ## Confirm if this status is already in the database
- $sql = "SELECT s.status_id, s.instance, s.repeat_instrument, s.record, s.project_id, s.event_id, s.field_name
- FROM redcap_data_quality_status s
- WHERE ".(($statusId == "" || !is_numeric($statusId)) ? "" : "s.status_id = '".db_escape($statusId)."'")."
- OR (s.record = '".db_escape($record)."'
- AND s.project_id = '".db_escape($projectId)."'
- AND s.event_id = '".db_escape($eventId)."'
- AND s.field_name = '".db_escape($fieldName)."'".
- ($repeatInstrument != NULL ? " AND s.repeat_instrument = '".db_escape($repeatInstrument)."'" :
- ($instance == NULL ? " AND s.instance is NULL" : " AND s.instance = '".db_escape($instance)."'")).")";
-
- $q = db_query($sql);
-
- ## Cache User ID to username conversion to reduce DB calls
- if(!array_key_exists($assignedUsername,$userIdConversion)) {
- $userIdConversion[$assignedUsername] = User::getUIIDByUsername($assignedUsername);
- }
-
- $existingStatus = "";
- while($row = db_fetch_assoc($q)) {
- ## Found a matching record/project/event/field/instance with a different status
- if($row['status_id'] != $statusId) {
- $existingStatus = $row['status_id'];
- $newStatusId = true;
- }
- ## Found a row for that statusId, verify if record/project/event/field/instance matches
- else if($row['record'] == $record && $row['project_id'] == $projectId
- && $row['event_id'] == $eventId && $row['field_name'] == $fieldName){
- if($instance == "" || $row['instance'] == $instance) {
- $existingStatus = $row['status_id'];
- $newStatusId = false;
- }
- }
- }
-
- ## Add new status row
- if($existingStatus == "") {
- $sql = "INSERT INTO redcap_data_quality_status
- (non_rule,project_id,record,event_id,field_name,instance,assigned_user_id)
- VALUES (1,".db_escape($projectId).",".db_escape($record).",".db_escape($eventId).",'".
- db_escape($fieldName)."',".checkNull($instance).",".checkNull($userIdConversion[$assignedUsername]).")";
-
- db_query($sql);
- $existingStatus = db_insert_id();
- $newStatusId = true;
- }
-
- ## Do date conversion on resolutions so they can be quickly sorted
- foreach($dataRow['resolutions'] as $resKey => $resolutionRow) {
- $dataRow['resolutions'][$resKey]['tsInSeconds'] = strtotime($resolutionRow['ts']);
- }
-
- ## Sort resolutions by timestamp and get last timestamp in DB
- usort($dataRow['resolutions'],function($a,$b) {
- if($a['tsInSeconds'] > $b['tsInSeconds']) {
- return 1;
- }
- else if($a['tsInSeconds'] == $b['tsInSeconds']) {
- return 0;
- }
- return -1;
- });
-
- $sql = "SELECT r.ts,r.user_id
- FROM redcap_data_quality_resolutions r
- WHERE r.status_id = '".$existingStatus."'
- ORDER BY r.ts DESC";
-
- $q = db_query($sql);
- $existingResolutions = array();
- while($row = db_fetch_assoc($q)) {
- $existingResolutions[$row['ts'].$row['user_id']] = 1;
- }
-
- $dbTs = db_result($q,0,"ts");
- $lastTs = "";
-
- foreach($dataRow['resolutions'] as $resolutionRow) {
- if($editComments) {
- # TODO Allow update of data resolution status/comments
- //DataQuality::editFieldComment();
- }
-
- // Determine the status to set
- if (in_array($resolutionRow['current_query_status'], array('OPEN','CLOSED','VERIFIED','DEVERIFIED'))) {
- $resStatus = $resolutionRow['current_query_status'];
- } elseif ((isset($resolutionRow['response_requested']) && $resolutionRow['response_requested'])
- || ($resolutionRow['response'] && $resolutionRow['response'])) {
- $resStatus = 'OPEN';
- } else {
- $resStatus = '';
- }
-
- // Make sure response is in enum list
- if(in_array($resolutionRow['response'],array('DATA_MISSING','TYPOGRAPHICAL_ERROR','CONFIRMED_CORRECT','WRONG_SOURCE','OTHER'))) {
- $response = $resolutionRow['response'];
- }
- else {
- $response = '';
- }
-
- $resolutionId = $resolutionRow['res_id'];
- $resStatusId = $resolutionRow['status_id'];
- $username = $resolutionRow['username'];
-
- ## Skip resolution rows that don't have matching status IDs unless this is a new status
- if(!$newStatusId && $resStatusId != "" && $resStatusId != $existingStatus) continue;
-
- ## Cache User ID to username conversion to reduce DB calls
- if(!array_key_exists($username,$userIdConversion)) {
- $userIdConversion[$username] = User::getUIIDByUsername($username);
- }
-
- ## Skip resolution rows that already have a resolution from the same user for the same timestamp
- ## This is to prevent duplicate response rows
- if(array_key_exists($resolutionRow['ts'].$userIdConversion[$username],$existingResolutions)) {
- continue;
- }
-
- $lastTs = $resolutionRow['ts'];
-
- $insertValues[] = "(".checkNull($existingStatus).",".checkNull($resolutionRow['ts']).",".
- checkNull($userIdConversion[$username]).",".(in_array($resolutionRow['response_requested'],[0,1]) ? $resolutionRow['response_requested'] : 0).",".
- checkNull($response).",".checkNull($resolutionRow['comment']).",".
- checkNull($resStatus).")";
-
- $existingResolutions[$resolutionRow['ts'].$userIdConversion[$username]] = 1;
-
- ## Do inserts in groups of 10 to reduce DB calls
- if(count($insertValues) >= 10) {
- $sql = "INSERT INTO redcap_data_quality_resolutions
- (status_id,ts,user_id,response_requested,response,comment,current_query_status)
- VALUES ".implode(",",$insertValues);
- db_query($sql);
-
- if($e = db_error()) {
- error_log("Data Quality Import: ".$e);
- }
- else {
- $nextId = db_insert_id();
- for($i = 0; $i < 10; $i++) {
- $resolutionInsertIds[] = $nextId + $i;
- }
- }
- $insertValues = [];
- }
- }
-
- ## If last timestamp is after last timestamp in DB, then update main query_status
- if($existingStatus && $lastTs != "" && strtotime($lastTs) > strtotime($dbTs)) {
- $sql = "UPDATE redcap_data_quality_status
- SET query_status = ".checkNull($resStatus)."
- WHERE status_id = ".$existingStatus;
-
- db_query($sql);
- }
- }
-
- if(count($insertValues) > 0) {
- ## Do last inserts pending in $insertValues
- $sql = "INSERT INTO redcap_data_quality_resolutions
- (status_id,ts,user_id,response_requested,response,comment,current_query_status)
- VALUES ".implode(",",$insertValues);
- db_query($sql);
-
- if($e = db_error()) {
- error_log("Data Quality Import: ".$e);
- }
- else {
- $nextId = db_insert_id();
- for($i = 0; $i < count($insertValues); $i++) {
- $resolutionInsertIds[] = $nextId + $i;
- }
- }
- $insertValues = [];
- }
-
- ## TODO Send other types of responses based on request
- $content = json_encode($resolutionInsertIds);
- return ($errors);
-
- function csv($data,$headers) {
- foreach($data as $dataRow) {
- foreach($headers as $column => $label) {
- if($label == "record") {
- ## If record is blank, this must be a data resolution row
- if($dataRow[$column] == "") {
-
- }
- ## Else, this must be a status row
- else {
-
- }
- }
- }
- }
- }
- }
}
diff --git a/importJsonFile.php b/importJsonFile.php
index 01366c1..f89d4b7 100644
--- a/importJsonFile.php
+++ b/importJsonFile.php
@@ -39,7 +39,7 @@
$dataCommentProcess = true;
}
else {
- array_push($errors, "Data may not be imported because the project does not have data quality enabled."));
+ array_push($errors, "Data may not be imported because the project does not have data quality enabled.");
}
if($projectSettings['field_comment_edit_delete'] == 1) {
@@ -51,251 +51,266 @@
$single_event = true;
}
-## TODO Convert flat/csv data into nested array format
-$importData = json_decode($post['import_file'],true);
-
-foreach($importData as $dataRow) {
- $statusId = $dataRow['status_id'];
- $record = $dataRow['record'];
- $projectId = $dataRow['project_id'];
- $eventId = $dataRow['event_id'];
- $fieldName = $dataRow['field_name'];
- $instance = $dataRow['instance'];
- $repeatInstrument = $dataRow['repeat_instrument'];
- $assignedUsername = $dataRow['assigned_username'];
- $newStatusId = false;
-
- ## Verify field name and event ID exist on this project. Skip this row if it doesn't
- if(!array_key_exists($fieldName,$Proj->metadata)) {
- continue;
- }
+// Import the json file
+if (isset($_FILES['import_file']) && $_FILES['import_file']['error'] === UPLOAD_ERR_OK) {
+ $importData = json_decode(file_get_contents($_FILES['import_file']['tmp_name']),true);
+}else{
+ array_push($errors, "File failed to upload");
+}
- $eventFound = false;
- foreach($Proj->events as $armDetails) {
- foreach($armDetails["events"] as $tempEventId => $eventDetails) {
- // check for non-longitudinal project
- if (count($armDetails['events']) == 1 && $single_event){
- $eventId = $tempEventId;
- $eventFound = true;
- break 2;
- }else if($eventId == $tempEventId) {
- $eventFound = true;
- break 2;
- }
+if(is_null($importData)){
+ array_push($errors, "Failed to decode json. Please ensure that the file selected was json...");
+ $content = NULL;
+}else{
+ foreach($importData as $dataRow) {
+ $statusId = $dataRow['status_id'];
+ $record = $dataRow['record'];
+ $projectId = $dataRow['project_id'];
+ $eventId = $dataRow['event_id'];
+ $fieldName = $dataRow['field_name'];
+ $instance = $dataRow['instance'];
+ $repeatInstrument = $dataRow['repeat_instrument'];
+ $assignedUsername = $dataRow['assigned_username'];
+ $newStatusId = false;
+
+ ## Verify field name and event ID exist on this project. Skip this row if it doesn't
+ if(!array_key_exists($fieldName,$Proj->metadata)) {
+ continue;
}
- }
- if(!$eventFound) {
- continue;
- }
+ $eventFound = false;
+ foreach($Proj->events as $armDetails) {
+ foreach($armDetails["events"] as $tempEventId => $eventDetails) {
+ // check for non-longitudinal project
+ if (count($armDetails['events']) == 1 && $single_event){
+ $eventId = $tempEventId;
+ $eventFound = true;
+ break 2;
+ }else if($eventId == $tempEventId) {
+ $eventFound = true;
+ break 2;
+ }
+ }
+ }
- ## Skip if record/project/event/field is blank
- if($record == "" || $projectId == "" || $eventId == "" || $fieldName == "") continue;
+ if(!$eventFound) {
+ continue;
+ }
- ## Skip data where the projectId doesn't match the token's projectId
- if($projectId != PROJECT_ID) continue;
+ ## Skip if record/project/event/field is blank
+ if($record == "" || $projectId == "" || $eventId == "" || $fieldName == "") continue;
+ ## Skip data where the projectId doesn't match the token's projectId
+ if($projectId != PROJECT_ID) continue;
- ## Confirm if this status is already in the database
- $sql = "SELECT s.status_id, s.instance, s.repeat_instrument, s.record, s.project_id, s.event_id, s.field_name
- FROM redcap_data_quality_status s
- WHERE ".(($statusId == "" || !is_numeric($statusId)) ? "" : "s.status_id = '".db_escape($statusId)."'")."
- OR (s.record = '".db_escape($record)."'
- AND s.project_id = '".db_escape($projectId)."'
- AND s.event_id = '".db_escape($eventId)."'
- AND s.field_name = '".db_escape($fieldName)."'".
- ($repeatInstrument != NULL ? " AND s.repeat_instrument = '".db_escape($repeatInstrument)."'" :
- ($instance == NULL ? " AND s.instance is NULL" : " AND s.instance = '".db_escape($instance)."'")).")";
- $q = db_query($sql);
+ ## Confirm if this status is already in the database
+ $sql = "SELECT s.status_id, s.instance, s.repeat_instrument, s.record, s.project_id, s.event_id, s.field_name
+ FROM redcap_data_quality_status s
+ WHERE ".(($statusId == "" || !is_numeric($statusId)) ? "" : "s.status_id = '".db_escape($statusId)."'")."
+ OR (s.record = '".db_escape($record)."'
+ AND s.project_id = '".db_escape($projectId)."'
+ AND s.event_id = '".db_escape($eventId)."'
+ AND s.field_name = '".db_escape($fieldName)."'".
+ ($repeatInstrument != NULL ? " AND s.repeat_instrument = '".db_escape($repeatInstrument)."'" :
+ ($instance == NULL ? " AND s.instance is NULL" : " AND s.instance = '".db_escape($instance)."'")).")";
- ## Cache User ID to username conversion to reduce DB calls
- if(!array_key_exists($assignedUsername,$userIdConversion)) {
- $userIdConversion[$assignedUsername] = User::getUIIDByUsername($assignedUsername);
- }
+ $q = db_query($sql);
- $existingStatus = "";
- while($row = db_fetch_assoc($q)) {
- ## Found a matching record/project/event/field/instance with a different status
- if($row['status_id'] != $statusId) {
- $existingStatus = $row['status_id'];
- $newStatusId = true;
+ ## Cache User ID to username conversion to reduce DB calls
+ if(!array_key_exists($assignedUsername,$userIdConversion)) {
+ $userIdConversion[$assignedUsername] = User::getUIIDByUsername($assignedUsername);
}
- ## Found a row for that statusId, verify if record/project/event/field/instance matches
- else if($row['record'] == $record && $row['project_id'] == $projectId
- && $row['event_id'] == $eventId && $row['field_name'] == $fieldName){
- if($instance == "" || $row['instance'] == $instance) {
+
+ $existingStatus = "";
+ while($row = db_fetch_assoc($q)) {
+ ## Found a matching record/project/event/field/instance with a different status
+ if($row['status_id'] != $statusId) {
$existingStatus = $row['status_id'];
- $newStatusId = false;
+ $newStatusId = true;
+ }
+ ## Found a row for that statusId, verify if record/project/event/field/instance matches
+ else if($row['record'] == $record && $row['project_id'] == $projectId
+ && $row['event_id'] == $eventId && $row['field_name'] == $fieldName){
+ if($instance == "" || $row['instance'] == $instance) {
+ $existingStatus = $row['status_id'];
+ $newStatusId = false;
+ }
}
}
- }
- ## Add new status row
- if($existingStatus == "") {
- $sql = "INSERT INTO redcap_data_quality_status
- (non_rule,project_id,record,event_id,field_name,instance,assigned_user_id)
- VALUES (1,".db_escape($projectId).",".db_escape($record).",".db_escape($eventId).",'".
- db_escape($fieldName)."',".checkNull($instance).",".checkNull($userIdConversion[$assignedUsername]).")";
-
- db_query($sql);
- $existingStatus = db_insert_id();
- $newStatusId = true;
- }
+ ## Add new status row
+ if($existingStatus == "") {
+ $sql = "INSERT INTO redcap_data_quality_status
+ (non_rule,project_id,record,event_id,field_name,instance,assigned_user_id)
+ VALUES (1,".db_escape($projectId).",".db_escape($record).",".db_escape($eventId).",'".
+ db_escape($fieldName)."',".checkNull($instance).",".checkNull($userIdConversion[$assignedUsername]).")";
- ## Do date conversion on resolutions so they can be quickly sorted
- foreach($dataRow['resolutions'] as $resKey => $resolutionRow) {
- $dataRow['resolutions'][$resKey]['tsInSeconds'] = strtotime($resolutionRow['ts']);
- }
+ db_query($sql);
+ $existingStatus = db_insert_id();
+ $newStatusId = true;
+ }
- ## Sort resolutions by timestamp and get last timestamp in DB
- usort($dataRow['resolutions'],function($a,$b) {
- if($a['tsInSeconds'] > $b['tsInSeconds']) {
- return 1;
+ ## Do date conversion on resolutions so they can be quickly sorted
+ foreach($dataRow['resolutions'] as $resKey => $resolutionRow) {
+ $dataRow['resolutions'][$resKey]['tsInSeconds'] = strtotime($resolutionRow['ts']);
}
- else if($a['tsInSeconds'] == $b['tsInSeconds']) {
- return 0;
+
+ ## Sort resolutions by timestamp and get last timestamp in DB
+ usort($dataRow['resolutions'],function($a,$b) {
+ if($a['tsInSeconds'] > $b['tsInSeconds']) {
+ return 1;
+ }
+ else if($a['tsInSeconds'] == $b['tsInSeconds']) {
+ return 0;
+ }
+ return -1;
+ });
+
+ $sql = "SELECT r.ts,r.user_id
+ FROM redcap_data_quality_resolutions r
+ WHERE r.status_id = '".$existingStatus."'
+ ORDER BY r.ts DESC";
+
+ $q = db_query($sql);
+ $existingResolutions = array();
+ while($row = db_fetch_assoc($q)) {
+ $existingResolutions[$row['ts'].$row['user_id']] = 1;
}
- return -1;
- });
-
- $sql = "SELECT r.ts,r.user_id
- FROM redcap_data_quality_resolutions r
- WHERE r.status_id = '".$existingStatus."'
- ORDER BY r.ts DESC";
-
- $q = db_query($sql);
- $existingResolutions = array();
- while($row = db_fetch_assoc($q)) {
- $existingResolutions[$row['ts'].$row['user_id']] = 1;
- }
- $dbTs = db_result($q,0,"ts");
- $lastTs = "";
+ $dbTs = db_result($q,0,"ts");
+ $lastTs = "";
- foreach($dataRow['resolutions'] as $resolutionRow) {
- if($editComments) {
- # TODO Allow update of data resolution status/comments
- //DataQuality::editFieldComment();
- }
+ foreach($dataRow['resolutions'] as $resolutionRow) {
+ if($editComments) {
+ # TODO Allow update of data resolution status/comments
+ //DataQuality::editFieldComment();
+ }
- // Determine the status to set
- if (in_array($resolutionRow['current_query_status'], array('OPEN','CLOSED','VERIFIED','DEVERIFIED'))) {
- $resStatus = $resolutionRow['current_query_status'];
- } elseif ((isset($resolutionRow['response_requested']) && $resolutionRow['response_requested'])
- || ($resolutionRow['response'] && $resolutionRow['response'])) {
- $resStatus = 'OPEN';
- } else {
- $resStatus = '';
- }
+ // Determine the status to set
+ if (in_array($resolutionRow['current_query_status'], array('OPEN','CLOSED','VERIFIED','DEVERIFIED'))) {
+ $resStatus = $resolutionRow['current_query_status'];
+ } elseif ((isset($resolutionRow['response_requested']) && $resolutionRow['response_requested'])
+ || ($resolutionRow['response'] && $resolutionRow['response'])) {
+ $resStatus = 'OPEN';
+ } else {
+ $resStatus = '';
+ }
- // Make sure response is in enum list
- if(in_array($resolutionRow['response'],array('DATA_MISSING','TYPOGRAPHICAL_ERROR','CONFIRMED_CORRECT','WRONG_SOURCE','OTHER'))) {
- $response = $resolutionRow['response'];
- }
- else {
- $response = '';
- }
+ // Make sure response is in enum list
+ if(in_array($resolutionRow['response'],array('DATA_MISSING','TYPOGRAPHICAL_ERROR','CONFIRMED_CORRECT','WRONG_SOURCE','OTHER'))) {
+ $response = $resolutionRow['response'];
+ }
+ else {
+ $response = '';
+ }
- $resolutionId = $resolutionRow['res_id'];
- $resStatusId = $resolutionRow['status_id'];
- $username = $resolutionRow['username'];
+ $resolutionId = $resolutionRow['res_id'];
+ $resStatusId = $resolutionRow['status_id'];
+ $username = $resolutionRow['username'];
- ## Skip resolution rows that don't have matching status IDs unless this is a new status
- if(!$newStatusId && $resStatusId != "" && $resStatusId != $existingStatus) continue;
+ ## Skip resolution rows that don't have matching status IDs unless this is a new status
+ if(!$newStatusId && $resStatusId != "" && $resStatusId != $existingStatus) continue;
- ## Cache User ID to username conversion to reduce DB calls
- if(!array_key_exists($username,$userIdConversion)) {
- $userIdConversion[$username] = User::getUIIDByUsername($username);
- }
+ ## Cache User ID to username conversion to reduce DB calls
+ if(!array_key_exists($username,$userIdConversion)) {
+ $userIdConversion[$username] = User::getUIIDByUsername($username);
+ }
- ## Skip resolution rows that already have a resolution from the same user for the same timestamp
- ## This is to prevent duplicate response rows
- if(array_key_exists($resolutionRow['ts'].$userIdConversion[$username],$existingResolutions)) {
- continue;
- }
+ ## Skip resolution rows that already have a resolution from the same user for the same timestamp
+ ## This is to prevent duplicate response rows
+ if(array_key_exists($resolutionRow['ts'].$userIdConversion[$username],$existingResolutions)) {
+ continue;
+ }
- $lastTs = $resolutionRow['ts'];
+ $lastTs = $resolutionRow['ts'];
- $insertValues[] = "(".checkNull($existingStatus).",".checkNull($resolutionRow['ts']).",".
- checkNull($userIdConversion[$username]).",".(in_array($resolutionRow['response_requested'],[0,1]) ? $resolutionRow['response_requested'] : 0).",".
- checkNull($response).",".checkNull($resolutionRow['comment']).",".
- checkNull($resStatus).")";
+ $insertValues[] = "(".checkNull($existingStatus).",".checkNull($resolutionRow['ts']).",".
+ checkNull($userIdConversion[$username]).",".(in_array($resolutionRow['response_requested'],[0,1]) ? $resolutionRow['response_requested'] : 0).",".
+ checkNull($response).",".checkNull($resolutionRow['comment']).",".
+ checkNull($resStatus).")";
- $existingResolutions[$resolutionRow['ts'].$userIdConversion[$username]] = 1;
+ $existingResolutions[$resolutionRow['ts'].$userIdConversion[$username]] = 1;
- ## Do inserts in groups of 10 to reduce DB calls
- if(count($insertValues) >= 10) {
- $sql = "INSERT INTO redcap_data_quality_resolutions
- (status_id,ts,user_id,response_requested,response,comment,current_query_status)
- VALUES ".implode(",",$insertValues);
- db_query($sql);
+ ## Do inserts in groups of 10 to reduce DB calls
+ if(count($insertValues) >= 10) {
+ $sql = "INSERT INTO redcap_data_quality_resolutions
+ (status_id,ts,user_id,response_requested,response,comment,current_query_status)
+ VALUES ".implode(",",$insertValues);
+ db_query($sql);
- if($e = db_error()) {
- error_log("Data Quality Import: ".$e);
- }
- else {
- $nextId = db_insert_id();
- for($i = 0; $i < 10; $i++) {
- $resolutionInsertIds[] = $nextId + $i;
+ if($e = db_error()) {
+ error_log("Data Quality Import: ".$e);
}
+ else {
+ $nextId = db_insert_id();
+ for($i = 0; $i < 10; $i++) {
+ $resolutionInsertIds[] = $nextId + $i;
+ }
+ }
+ $insertValues = [];
}
- $insertValues = [];
}
- }
- ## If last timestamp is after last timestamp in DB, then update main query_status
- if($existingStatus && $lastTs != "" && strtotime($lastTs) > strtotime($dbTs)) {
- $sql = "UPDATE redcap_data_quality_status
- SET query_status = ".checkNull($resStatus)."
- WHERE status_id = ".$existingStatus;
+ ## If last timestamp is after last timestamp in DB, then update main query_status
+ if($existingStatus && $lastTs != "" && strtotime($lastTs) > strtotime($dbTs)) {
+ $sql = "UPDATE redcap_data_quality_status
+ SET query_status = ".checkNull($resStatus)."
+ WHERE status_id = ".$existingStatus;
- db_query($sql);
+ db_query($sql);
+ }
}
-}
-if(count($insertValues) > 0) {
- ## Do last inserts pending in $insertValues
- $sql = "INSERT INTO redcap_data_quality_resolutions
- (status_id,ts,user_id,response_requested,response,comment,current_query_status)
- VALUES ".implode(",",$insertValues);
- db_query($sql);
+ if(count($insertValues) > 0) {
+ ## Do last inserts pending in $insertValues
+ $sql = "INSERT INTO redcap_data_quality_resolutions
+ (status_id,ts,user_id,response_requested,response,comment,current_query_status)
+ VALUES ".implode(",",$insertValues);
+ db_query($sql);
- if($e = db_error()) {
- error_log("Data Quality Import: ".$e);
- }
- else {
- $nextId = db_insert_id();
- for($i = 0; $i < count($insertValues); $i++) {
- $resolutionInsertIds[] = $nextId + $i;
+ if($e = db_error()) {
+ error_log("Data Quality Import: ".$e);
+ }
+ else {
+ $nextId = db_insert_id();
+ for($i = 0; $i < count($insertValues); $i++) {
+ $resolutionInsertIds[] = $nextId + $i;
+ }
}
+ $insertValues = [];
}
- $insertValues = [];
+
+ ## TODO Send other types of responses based on request
+ $content = json_encode($resolutionInsertIds);
}
-## TODO Send other types of responses based on request
-$content = json_encode($resolutionInsertIds);
+
# Send the response to the requestor
// RestUtility::sendResponse(200, $content, $format);
-$dataQualityExternalModule = new \Vanderbilt\DataQualityExternalModule\DataQualityExternalModule();
-$errors = $dataQualityExternalModule->import_json_file();
-
if (!empty($errors))
{
- require_once APP_PATH_DOCROOT . 'ProjectGeneral/header.php';
- print "";
- foreach($errors as $error)
- {
- print "
$error
";
- }
- print "
";
- require_once APP_PATH_DOCROOT . 'ProjectGeneral/footer.php';
+ require_once APP_PATH_DOCROOT . 'ProjectGeneral/header.php';
+ print "";
+ foreach($errors as $error)
+ {
+ print "
$error
";
+ }
+ print "
";
+ require_once APP_PATH_DOCROOT . 'ProjectGeneral/footer.php';
}
else
{
- header("Location: " . $dataQualityExternalModule->getUrl("index.php") . "&imported=1");
+ // $dataQualityExternalModule = new \Vanderbilt\DataQualityExternalModule\DataQualityExternalModule();
+ // $errors = $dataQualityExternalModule->import_json_file();
+ // header("Location: " . $dataQualityExternalModule->getUrl("index.php") . "&imported=1");
+ require_once APP_PATH_DOCROOT . 'ProjectGeneral/header.php';
+ print "";
+ print "
SUCCESS:$content
";
+ print "
";
+ require_once APP_PATH_DOCROOT . 'ProjectGeneral/footer.php';
}
function csv($data,$headers) {
From d3a18e19ef184d65c2da9ad517f340d665052e61 Mon Sep 17 00:00:00 2001
From: devincowan
Date: Mon, 5 Oct 2020 12:40:02 -0600
Subject: [PATCH 3/8] success message
---
importJsonFile.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/importJsonFile.php b/importJsonFile.php
index f89d4b7..044cd60 100644
--- a/importJsonFile.php
+++ b/importJsonFile.php
@@ -308,7 +308,7 @@
// header("Location: " . $dataQualityExternalModule->getUrl("index.php") . "&imported=1");
require_once APP_PATH_DOCROOT . 'ProjectGeneral/header.php';
print "";
- print "
SUCCESS:$content
";
+ print "
RES IDS MODIFIED:$content
";
print "
";
require_once APP_PATH_DOCROOT . 'ProjectGeneral/footer.php';
}
From 21da7ce49f3e8d2a3bd098cad312073c3ce72720 Mon Sep 17 00:00:00 2001
From: devincowan
Date: Mon, 5 Oct 2020 17:31:50 -0600
Subject: [PATCH 4/8] overwrite PID on file import
---
importJsonFile.php | 6 +++++-
index.php | 1 +
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/importJsonFile.php b/importJsonFile.php
index 044cd60..4d902a2 100644
--- a/importJsonFile.php
+++ b/importJsonFile.php
@@ -101,7 +101,11 @@
if($record == "" || $projectId == "" || $eventId == "" || $fieldName == "") continue;
## Skip data where the projectId doesn't match the token's projectId
- if($projectId != PROJECT_ID) continue;
+ // if($projectId != PROJECT_ID) continue;
+
+ // Allow imports from other projects--bypassing project ID
+ $projectId = PROJECT_ID;
+
## Confirm if this status is already in the database
diff --git a/index.php b/index.php
index 76a1938..5be13c9 100644
--- a/index.php
+++ b/index.php
@@ -25,6 +25,7 @@
Imported
+ Note PID will be ignored on import, so it is possible to import DRW data from other projects...