11import requests
2- from qualtrics_settings import BASE_URL , HEADERS , QualtricsAPIError
32import time
43import zipfile
54import io
65import pandas as pd
6+ import json
7+
8+ with open ("new_ldot_workflows/qualtrics_config.json" ) as f :
9+ config = json .load (f )
10+ QUALTRICS_BASE_URL = config ["QUALTRICS_BASE_URL" ]
11+ HEADERS = config ["HEADERS" ]
12+
13+ with open ("new_ldot_workflows/ldot_config.json" ) as f :
14+ config = json .load (f )
15+ CLIENT_ID = config ["client_id" ]
16+ CLIENT_SECRET = config ["client_secret" ]
17+ LDOT_API_URL = config ["LDOT_API_URL" ]
18+
19+ class QualtricsAPIError (Exception ):
20+ """Custom exception for Qualtrics API errors"""
21+ pass
722
823def create_data_export (survey_id : str , incomplete_bool : bool = True ) -> str :
924 """Create a data export request for a given survey.
@@ -17,7 +32,7 @@ def create_data_export(survey_id: str, incomplete_bool: bool = True) -> str:
1732 str: The ID of the data export request.
1833 """
1934 print ("Creating data export request... " )
20- endpoint = f"{ BASE_URL } /surveys/{ survey_id } /export-responses"
35+ endpoint = f"{ QUALTRICS_BASE_URL } /surveys/{ survey_id } /export-responses"
2136 payload = {
2237 "format" : "csv" ,
2338 "exportResponsesInProgress" : incomplete_bool
@@ -51,7 +66,7 @@ def check_export_progress(request_id: str, survey_id: str, returns: str) -> str|
5166 str: The percent complete if the request is still processing, or the file ID if complete.
5267 """
5368 print ("Checking on export progress... " )
54- endpoint = f"{ BASE_URL } /surveys/{ survey_id } /export-responses/{ request_id } "
69+ endpoint = f"{ QUALTRICS_BASE_URL } /surveys/{ survey_id } /export-responses/{ request_id } "
5570 try :
5671 result = requests .get (endpoint , headers = HEADERS )
5772 result .raise_for_status ()
@@ -84,7 +99,7 @@ def download_export(file_id: str, survey_id: str) -> pd.DataFrame:
8499 pd.DataFrame: The survey response data as a DataFrame.
85100 """
86101 print ("Downloading export file... " )
87- endpoint = f"{ BASE_URL } /surveys/{ survey_id } /export-responses/{ file_id } /file"
102+ endpoint = f"{ QUALTRICS_BASE_URL } /surveys/{ survey_id } /export-responses/{ file_id } /file"
88103 try :
89104 download = requests .get (
90105 endpoint ,
@@ -133,6 +148,7 @@ def check_inputs_validity(participant_study_id: str, embedded_data_field: str, s
133148 raise ValueError ("Invalid participant_study_id. It should be a non-empty string." )
134149 return True
135150
151+
136152def get_responses_as_df (survey_id : str , incomplete_bool : bool ) -> pd .DataFrame :
137153 """Wrapper function to request export, wait for it, download it, and convert to DataFrame.
138154
@@ -157,13 +173,49 @@ def get_responses_as_df(survey_id: str, incomplete_bool: bool) -> pd.DataFrame:
157173 df = download_export (file_id , survey_id )
158174 return df
159175
160- def get_individual_progress (participant_study_ids : list , embedded_data_field : str , survey_id : str ) -> float :
176+
177+ def subject_id_to_study_identifier (ldot_study_id : str , id_deelnemer_entity : str , id_location : str , subject_ids : list ) -> str :
178+ """Post the Qualtrics links back to Ldot for new subjects"""
179+
180+ response = requests .post (
181+ "https://accware.memic.maastrichtuniversity.nl/ldot_identity_server/connect/token" ,
182+ data = {
183+ "grant_type" : "client_credentials" ,
184+ "client_id" : CLIENT_ID ,
185+ "client_secret" : CLIENT_SECRET
186+ }
187+ )
188+ token = response .json ()["access_token" ]
189+ headers = {"accept" : "application/json" ,
190+ "Authorization" : f"Bearer { token } "
191+ }
192+
193+ subject_id_to_study_identifier_dict = {}
194+ for subject_id in subject_ids :
195+ # Populate the Qualtrics link in Ldot for the subject
196+ response = requests .post (
197+ f"https://accware.memic.maastrichtuniversity.nl/memic_ldot_api/api/v1.1/{ ldot_study_id } /Subject/" ,
198+ headers = headers ,
199+ json = {
200+ "subjectGuid" : subject_id ,
201+ "entityId" : id_deelnemer_entity ,
202+ "locationSubjectId" : id_location ,
203+ "doOverwriteNulls" : False ,
204+ }
205+ )
206+ subject_id_to_study_identifier_dict [subject_id ] = response .json ().get ("Data" , {}).get ("Subject" ).get ("RegistrationId" )
207+
208+
209+ return subject_id_to_study_identifier_dict
210+
211+
212+ def get_individual_progress (ldot_study_id : str , id_deelnemer_entity : str , id_location : str , subject_ids : list , embedded_data_field : str , survey_id : str ) -> float :
161213 """Wrapper function that gets the individual progress of a participant in a survey."""
162214 # Check for invalid inputs
215+ check_inputs_validity (subject_ids [0 ], embedded_data_field , survey_id ) # TODO: Check this
163216
164217 participant_to_progress_dict = {}
165-
166- check_inputs_validity (participant_study_ids [0 ], embedded_data_field , survey_id )
218+ subject_id_to_study_identifier_dict = subject_id_to_study_identifier (ldot_study_id , id_deelnemer_entity , id_location , subject_ids )
167219
168220 completed_responses_df = get_responses_as_df (survey_id , incomplete_bool = False )
169221 incompleted_responses_df = get_responses_as_df (survey_id , incomplete_bool = True )
@@ -172,21 +224,31 @@ def get_individual_progress(participant_study_ids: list, embedded_data_field: st
172224 if not embedded_data_field in df .columns :
173225 raise QualtricsAPIError (f"Embedded data field '{ embedded_data_field } ' not found in survey data. Please check the field name." )
174226
175- for participant_study_id in participant_study_ids :
176- individual_progress = df [df [embedded_data_field ] == participant_study_id ]
227+ for subject_id , study_identifier in subject_id_to_study_identifier_dict .items ():
228+ individual_progress = df [df [embedded_data_field ] == study_identifier ]
229+ print ("This is the individual progress for subject_id {}, study_identifier {}: {}" .format (subject_id , study_identifier , individual_progress ))
177230 if not individual_progress .empty :
178231 individual_progress = individual_progress ["Progress" ].values [0 ]
179- participant_to_progress_dict [participant_study_id ] = individual_progress
232+ participant_to_progress_dict [subject_id ] = individual_progress
180233 else :
181- participant_to_progress_dict [participant_study_id ] = None # or some indicator that the participant ID was not found in the data
234+ participant_to_progress_dict [subject_id ] = 0 # Indicator that the subject ID was not found in the data
182235
183236 return participant_to_progress_dict
184237
185238if __name__ == "__main__" :
186- # Example usage
187- participant_study_ids = ["11111TEST11111" , "22222TEST22222" , "33333TEST33333" ]
239+ # # Example usage
188240 survey_id = "SV_efCMOg6wHU0T8ii"
189241 embedded_data_field = "study_id_child"
190242
191- participant_to_progress_dict = get_individual_progress (participant_study_ids , embedded_data_field , survey_id )
192- print (participant_to_progress_dict )
243+
244+ ldot_study_id = "5c9c6a47-c8d7-8142-a8c8-ccdcb8a8044b"
245+ subject_ids = ["352fb9d8-962f-4735-9fc7-7b4e18109a51" ]
246+ id_deelnemer_entity = "7f61b810-00ed-1d41-8a33-4164f25ebad0"
247+ id_location = "427f304f-9d95-44f5-8f7b-d6a1ce1db293"
248+ embedded_data_field = "study_id_child"
249+
250+ participant_to_progress_dict = get_individual_progress (ldot_study_id , id_deelnemer_entity , id_location , subject_ids , embedded_data_field , survey_id )
251+ print (participant_to_progress_dict )
252+
253+
254+ # subject_id_to_study_identifier_dict = subject_id_to_study_identifier(ldot_study_id, id_deelnemer_entity, id_location, subject_ids)
0 commit comments