Skip to content

Commit c0707d3

Browse files
author
“Carmel
committed
Create qualtrics link for a participant identifier converted from the api subjectID
1 parent a2680d1 commit c0707d3

13 files changed

Lines changed: 136 additions & 91 deletions

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
venv/
22
new_ldot_workflows/ldot_config.json
3-
new_ldot_workflows/qualtrics_settings.py
3+
new_ldot_workflows/qualtrics_config.json
4+
45
scratch.py

app.py

Lines changed: 32 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from new_ldot_workflows.b_2_get_qualtrics_links import add_individuals_to_survey
99
from new_ldot_workflows.b_2_send_links_to_ldot import send_links_to_ldot
1010
from new_ldot_workflows.b_3_get_incomplete_subjects import get_incomplete_subjects
11-
from new_ldot_workflows.b_4_get_individual_progress import get_individual_progress
11+
# from new_ldot_workflows.b_4_get_individual_progress import get_individual_progress
1212

1313
app = Flask(__name__)
1414

@@ -54,7 +54,7 @@ def button2():
5454
"""Uses subjectIDs from button 1 to add them to Qualtrics and send the links back to LDOT"""
5555
data = request.json
5656
study_id = data.get("study_id")
57-
new_subject_ids = data.get("new_subject_ids")
57+
new_subject_ids = data.get("new_subject_ids") or data.get("subject_ids")
5858

5959
if not study_id:
6060
return jsonify({"success": False, "message": "Missing study_id in request"}), 400
@@ -66,21 +66,20 @@ def button2():
6666
study, ldot_vars, qualtrics_vars = get_study_settings(study_id)
6767

6868
ldot_study_id = ldot_vars.get("ldot_study_id")
69+
eaid_deelnemer_entity = ldot_vars.get("eaid_deelnemer_entity")
6970
qualtrics_survey_id = qualtrics_vars.get("survey_id")
7071
mailing_list_id = qualtrics_vars.get("mailing_list_id")
7172
embedded_data_field = qualtrics_vars.get("embedded_data_field")
7273
directory_id = qualtrics_vars.get("directory_id")
7374
distribution_id = qualtrics_vars.get("distribution_id")
7475

75-
76-
# link_creation_eaid = ldot_vars.get("eaid_qualtrics_survey_link_creation_to_do_date") or ldot_vars.get("eaid_qualtrics_survey_link_creation_completed")
77-
7876
if not ldot_study_id:
7977
return jsonify({"success": False, "message": f"Missing ldot_study_id for study_id: {study_id}"}), 400
8078

8179
debug_inputs = {
8280
"study_id": study_id,
8381
"ldot_study_id": ldot_study_id,
82+
"eaid_deelnemer_entity": eaid_deelnemer_entity,
8483
"new_subject_ids": new_subject_ids,
8584
"qualtrics_survey_id": qualtrics_survey_id,
8685
"mailing_list_id": mailing_list_id,
@@ -89,14 +88,14 @@ def button2():
8988
"distribution_id": distribution_id
9089
}
9190

92-
participant_to_link_dict = add_individuals_to_survey(new_subject_ids, embedded_data_field, distribution_id, qualtrics_survey_id, mailing_list_id, directory_id)
93-
# send_links_to_ldot(ldot_study_id, link_creation_eaid)
91+
subject_id_to_link_dict = add_individuals_to_survey(new_subject_ids, ldot_study_id, eaid_deelnemer_entity, embedded_data_field, distribution_id, qualtrics_survey_id, mailing_list_id, directory_id)
92+
send_links_to_ldot(ldot_study_id, eaid_deelnemer_entity, subject_id_to_link_dict)
9493

9594
return jsonify({
9695
"success": True,
97-
"message": f"Processed {len(new_subject_ids)} subject IDs for study {study_id}",
96+
"message": f"Processed {len(new_subject_ids)} subject IDs",
9897
"debug_inputs": debug_inputs,
99-
"participant_to_link_dict": participant_to_link_dict,
98+
"subject_id_to_link_dict": subject_id_to_link_dict
10099
})
101100

102101

@@ -111,17 +110,14 @@ def button3():
111110
return jsonify({"success": False, "message": f"Unknown study_id: {study_id}"}), 400
112111

113112
ldot_study_id = ldot_vars.get("ldot_study_id")
114-
survey_progress_wait_for_entry_eaid = ldot_vars.get("survey_progress_wait_for_entry_eaid")
115-
survey_progress_completed_eaid = ldot_vars.get("survey_progress_completed_eaid")
116-
117-
if not ldot_study_id:
118-
return jsonify({"success": False, "message": f"Missing ldot_study_id for study_id: {study_id}"}), 400
113+
eaid_survey_invitation_completed = ldot_vars.get("eaid_survey_invitation_completed")
114+
eaid_survey_progress_completed = ldot_vars.get("eaid_survey_progress_completed")
119115

120116
try:
121117
result = f"Button 3 executed for study {study_id}"
122118
# Return both message and subject_ids list
123-
incomplete_subjects = get_incomplete_subjects(ldot_study_id, survey_progress_wait_for_entry_eaid, survey_progress_completed_eaid)
124-
return jsonify({"success": True, "message": result, "subject_ids": incomplete_subjects})
119+
subjects_not_completed_survey = get_incomplete_subjects(ldot_study_id, eaid_survey_invitation_completed, eaid_survey_progress_completed)
120+
return jsonify({"success": True, "message": result, "subject_ids": subjects_not_completed_survey})
125121
except Exception as e:
126122
return jsonify({"success": False, "message": str(e)})
127123

@@ -130,33 +126,33 @@ def button3():
130126
def button4():
131127
"""Fourth API call - uses subjectIDs from button3"""
132128
data = request.json
133-
study_id = data.get("study_id")
134-
subject_ids = data.get("subject_ids") # List of subjectIDs from button3
129+
# study_id = data.get("study_id")
130+
# subject_ids = data.get("subject_ids") # List of subjectIDs from button3
135131

136-
if not study_id:
137-
return jsonify({"success": False, "message": "Missing study_id in request"}), 400
132+
# if not study_id:
133+
# return jsonify({"success": False, "message": "Missing study_id in request"}), 400
138134

139-
if not subject_ids:
140-
return jsonify({"success": False, "message": "Missing subject_ids in request"}), 400
135+
# if not subject_ids:
136+
# return jsonify({"success": False, "message": "Missing subject_ids in request"}), 400
141137

142-
study, vars = get_study_settings(study_id)
143-
if not study:
144-
return jsonify({"success": False, "message": f"Unknown study_id: {study_id}"}), 400
138+
# study, vars = get_study_settings(study_id)
139+
# if not study:
140+
# return jsonify({"success": False, "message": f"Unknown study_id: {study_id}"}), 400
145141

146-
qualtrics_survey_id = vars.get("qualtrics_survey_id")
147-
embedded_data_field = vars.get("embedded_data_field")
142+
# qualtrics_survey_id = vars.get("qualtrics_survey_id")
143+
# embedded_data_field = vars.get("embedded_data_field")
148144

149-
participant_to_progress_dict = get_individual_progress(subject_ids, embedded_data_field, qualtrics_survey_id)
145+
# participant_to_progress_dict = get_individual_progress(subject_ids, embedded_data_field, qualtrics_survey_id)
150146

151147

152-
return jsonify({
153-
"success": True,
154-
"message": f"Retrieved progress for {len(participant_to_progress_dict)} subjects",
155-
"study_id": study_id,
156-
"qualtrics_survey_id": qualtrics_survey_id,
157-
"embedded_data_field": embedded_data_field,
158-
"progress_results": participant_to_progress_dict,
159-
})
148+
# return jsonify({
149+
# "success": True,
150+
# "message": f"Retrieved progress for {len(participant_to_progress_dict)} subjects",
151+
# "study_id": study_id,
152+
# "qualtrics_survey_id": qualtrics_survey_id,
153+
# "embedded_data_field": embedded_data_field,
154+
# "progress_results": participant_to_progress_dict,
155+
# })
160156

161157

162158
if __name__ == "__main__":
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

new_ldot_workflows/b_1_get_new_subjects.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
CLIENT_SECRET = config["client_secret"]
88
LDOT_API_URL = config["LDOT_API_URL"]
99

10-
def get_new_subjects(study_id: str, link_creation_eaid: str) -> list:
10+
def get_new_subjects(study_id: str, eaid_qualtrics_survey_link_creation_to_do_date: str) -> list:
1111
"""Get subjects that have not yet been added to Qualtrics by checking their event actions"""
1212

1313
response = requests.post(
@@ -26,7 +26,7 @@ def get_new_subjects(study_id: str, link_creation_eaid: str) -> list:
2626
}
2727

2828
response = requests.get(
29-
f"https://accware.memic.maastrichtuniversity.nl/memic_ldot_api/api/v1.1/{study_id}/Action/{link_creation_eaid}",
29+
f"https://accware.memic.maastrichtuniversity.nl/memic_ldot_api/api/v1.1/{study_id}/Action/{eaid_qualtrics_survey_link_creation_to_do_date}",
3030
headers=headers
3131
)
3232

new_ldot_workflows/b_2_get_qualtrics_links.py

Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,20 @@
33

44
with open("new_ldot_workflows/qualtrics_config.json") as f:
55
config = json.load(f)
6-
CLIENT_ID = config["client_id"]
7-
CLIENT_SECRET = config["client_secret"]
86
QUALTRICS_BASE_URL = config["QUALTRICS_BASE_URL"]
7+
HEADERS = config["HEADERS"]
98

9+
with open("new_ldot_workflows/ldot_config.json") as f:
10+
config = json.load(f)
11+
CLIENT_ID = config["client_id"]
12+
CLIENT_SECRET = config["client_secret"]
13+
LDOT_API_URL = config["LDOT_API_URL"]
1014

15+
class QualtricsAPIError(Exception):
16+
"""Custom exception for Qualtrics API errors"""
17+
pass
1118

12-
def check_contact_in_mailing_list(participant_study_id: str, mailing_list_id: str, directory_id: str) -> bool:
19+
def check_contact_in_mailing_list(study_identifier: str, mailing_list_id: str, directory_id: str) -> bool:
1320
"""Find who is already in that mailing list, check if the participant's ID is already there."""
1421

1522
print("Checking for contact in mailing list... ")
@@ -29,18 +36,18 @@ def check_contact_in_mailing_list(participant_study_id: str, mailing_list_id: st
2936

3037
contact_external_data_references = [contact["extRef"] for contact in contacts if "extRef" in contact]
3138

32-
if participant_study_id not in contact_external_data_references:
39+
if study_identifier not in contact_external_data_references:
3340
return False
3441
return True
3542

36-
def add_contact_to_mailing_list(participant_study_id: str, embedded_data_field: str, mailing_list_id: str, directory_id: str) -> None:
43+
def add_contact_to_mailing_list(study_identifier: str, embedded_data_field: str, mailing_list_id: str, directory_id: str) -> None:
3744
"""Add contact to a mailing list"""
3845

3946
endpoint = f"{QUALTRICS_BASE_URL}/directories/{directory_id}/mailinglists/{mailing_list_id}/contacts"
4047
contact_information_payload ={
41-
"extRef": participant_study_id,
48+
"extRef": study_identifier,
4249
"embeddedData": {
43-
embedded_data_field: participant_study_id
50+
embedded_data_field: study_identifier
4451
}
4552
}
4653
try:
@@ -56,11 +63,11 @@ def add_contact_to_mailing_list(participant_study_id: str, embedded_data_field:
5663
f"Unexpected response format when adding contact to mailing list."
5764
) from exc
5865

59-
def get_personal_link(qualtrics_survey_id: str, distribution_id: str, participant_study_id: str) -> str:
66+
def get_personal_link(qualtrics_survey_id: str, distribution_id: str, study_identifier: str) -> str:
6067
"""Get the person link of an individual for a specified survey. Returns personal link for the participant, looks like
6168
https://survey.uu.nl/jfe/form/SV_efCMOg6wHU0T8ii?Q_CHLqe2Pdrma&_g_=g
6269
"""
63-
print(f"Fetching personal link for {participant_study_id}... ")
70+
print(f"Fetching personal link for {study_identifier}... ")
6471
endpoint = f"{QUALTRICS_BASE_URL}/distributions/{distribution_id}/links"
6572
parameters = {
6673
"surveyId": str(qualtrics_survey_id)
@@ -69,45 +76,78 @@ def get_personal_link(qualtrics_survey_id: str, distribution_id: str, participan
6976
response = requests.get(endpoint, headers=HEADERS, params=parameters)
7077
response.raise_for_status()
7178
data = response.json()
72-
personal_link = [item["link"] for item in data["result"]["elements"] if ("externalDataReference" in item) and (item["externalDataReference"] == participant_study_id)][0]
79+
personal_link = [item["link"] for item in data["result"]["elements"] if ("externalDataReference" in item) and (item["externalDataReference"] == study_identifier)][0]
7380
return personal_link
7481

7582
except requests.exceptions.RequestException as exc:
7683
raise QualtricsAPIError(
77-
f"Error while fetching personal link of individual {participant_study_id}."
84+
f"Error while fetching personal link of individual {study_identifier}."
7885
) from exc
7986
except (KeyError, TypeError, ValueError) as exc:
8087
raise QualtricsAPIError(
81-
f"Unexpected response format when fetching personal link of individual {participant_study_id}."
88+
f"Unexpected response format when fetching personal link of individual {study_identifier}."
8289
) from exc
8390

84-
def add_individuals_to_survey(participant_ids_list: list, embedded_data_field, distribution_id, qualtrics_survey_id, mailing_list_id, directory_id):
91+
def add_individuals_to_survey(new_subject_ids: list, ldot_study_id: str, eaid_deelnemer_entity: str, embedded_data_field: str, distribution_id: str, qualtrics_survey_id: str, mailing_list_id: str, directory_id: str):
92+
def convert_api_subject_id_to_study_identifier(api_subject_id):
93+
"""Convert subject ID used by the Ldot API to study identifier that can be used in Qualtrics surveys"""
94+
95+
response = requests.post(
96+
"https://accware.memic.maastrichtuniversity.nl/ldot_identity_server/connect/token",
97+
data={
98+
"grant_type": "client_credentials",
99+
"client_id": CLIENT_ID,
100+
"client_secret": CLIENT_SECRET
101+
}
102+
)
103+
token = response.json()["access_token"]
104+
headers={"accept": "application/json",
105+
"Authorization": f"Bearer {token}"
106+
}
107+
108+
response = requests.get(
109+
f"https://accware.memic.maastrichtuniversity.nl/memic_ldot_api/api/v1.1/{ldot_study_id}/Entity/{eaid_deelnemer_entity}",
110+
headers=headers
111+
)
112+
113+
subject_ids = response.json().get("Data", {}).get("SubjectIds")
114+
guid_to_registration_id = {subject["Guid"]: subject["RegistrationId"] for subject in subject_ids if "Guid" in subject and "RegistrationId" in subject}
115+
116+
study_identifier = guid_to_registration_id.get(api_subject_id)
117+
return study_identifier
118+
119+
85120
participant_to_link_dict = {}
86-
for participant_id in participant_ids_list:
87-
contact_exists = check_contact_in_mailing_list(participant_id, mailing_list_id, directory_id)
121+
for subject_id in new_subject_ids:
122+
study_identifier = convert_api_subject_id_to_study_identifier(subject_id)
123+
print(f"Processing subject ID: {subject_id} (Study Identifier: {study_identifier})")
124+
125+
contact_exists = check_contact_in_mailing_list(study_identifier, mailing_list_id, directory_id)
88126

89127
if not contact_exists:
90-
add_contact_to_mailing_list(participant_id, embedded_data_field, mailing_list_id, directory_id)
128+
print(f"Adding participant study ID {study_identifier} to mailing list...")
129+
add_contact_to_mailing_list(study_identifier, embedded_data_field, mailing_list_id, directory_id)
91130
else:
92-
print(f"Participant study ID {participant_id} already exists in this mailing list")
131+
print(f"Participant study ID {study_identifier} already exists in this mailing list")
93132

94-
personal_link = get_personal_link(qualtrics_survey_id, distribution_id, participant_id)
133+
personal_link = get_personal_link(qualtrics_survey_id, distribution_id, study_identifier)
95134

96-
participant_to_link_dict[participant_id] = personal_link
135+
participant_to_link_dict[subject_id] = personal_link
97136

98137
return participant_to_link_dict
99138

100139
if __name__ == "__main__":
101140
# # Example usage
102-
participant_study_id = ["11111TEST11111", "22222TEST22222", "33333TEST33333"]
141+
participant_study_id = ["352fb9d8-962f-4735-9fc7-7b4e18109a51"]
142+
ldot_study_id = "5c9c6a47-c8d7-8142-a8c8-ccdcb8a8044b"
143+
eaid_deelnemer_entity = "7f61b810-00ed-1d41-8a33-4164f25ebad0"
103144
embedded_data_field = "study_id_child"
104145
qualtrics_survey_id="SV_efCMOg6wHU0T8ii"
105146
mailing_list_id="CG_2dMbO6WUBMnCeIK"
106147
distribution_id="EMD_7AEa416lRwFhrkF"
107148
directory_id="POOL_10pyxk9leSUisrT"
108149

109-
110-
link = add_individuals_to_survey(participant_study_id, embedded_data_field, distribution_id, qualtrics_survey_id, mailing_list_id, directory_id)
150+
link = add_individuals_to_survey(participant_study_id, ldot_study_id, eaid_deelnemer_entity, embedded_data_field, distribution_id, qualtrics_survey_id, mailing_list_id, directory_id)
111151

112152
print(link)
113153

new_ldot_workflows/b_2_send_links_to_ldot.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313

1414
#### I then need to flip it to the next status
1515

16-
def send_links_to_ldot(study_id: str, link_creation_eaid: str) -> list:
17-
"""Get subjects that have not yet been added to Qualtrics by checking their event actions"""
16+
def send_links_to_ldot(study_id: str, eaid_deelnemer_entity, subject_id_to_link_dict: dict) -> list:
17+
"""Post the Qualtrics links back to Ldot for new subjects"""
1818

1919
response = requests.post(
2020
"https://accware.memic.maastrichtuniversity.nl/ldot_identity_server/connect/token",
@@ -48,4 +48,7 @@ def send_links_to_ldot(study_id: str, link_creation_eaid: str) -> list:
4848
# ]
4949

5050
if __name__ == "__main__":
51-
print(send_links_to_ldot("5c9c6a47-c8d7-8142-a8c8-ccdcb8a8044b", "5d31129c-d814-5d4b-a96f-048cadc150ce"))
51+
study_id = "5c9c6a47-c8d7-8142-a8c8-ccdcb8a8044b"
52+
subject_id_to_link_dict = {'352fb9d8-962f-4735-9fc7-7b4e18109a51': 'https://survey.uu.nl/jfe/form/SV_efCMOg6wHU0T8ii?Q_CHL=gl&Q_DL=EMD_7AEa416lRwFhrkF_efCMOg6wHU0T8ii_CGC_4WW2MwOaEB01XsM&_g_=g'}
53+
54+
send_links_to_ldot(study_id, subject_id_to_link_dict)

0 commit comments

Comments
 (0)