const readJwt = function (req) {
const authHeader = req.headers.authorization;
if (authHeader) {
const theJwtToken = authHeader.substring(7);
if (theJwtToken) {
const jwtBase64Encoded = theJwtToken.split(".")[1];
if (jwtBase64Encoded) {
const jwtDecoded = Buffer.from(jwtBase64Encoded, "base64").toString(
"ascii"
);
return JSON.parse(jwtDecoded);
}
}
}
};
---
applications:
- name: qualtricssentiments
routes:
- route: sap-qualtricssentiments.cfapps.eu10.hana.ondemand.com
path: ./
memory: 128M
buildpack: python_buildpack
command: python QualtricsExportSurveyResponsesAPI.py
import sys
import requests
import zipfile, io
import getpass
import pandas as pd
import datetime
from dateutil.relativedelta import relativedelta#
from os import *
### Define extraction parameters
## add your surveyid
surveyId = ""
dataCenter = 'fra1'
dataFormat = 'csv'
missingValues = -9
### Define today - 5 days in Qualtrics freindly format
today_time = datetime.datetime.now()
today_time = today_time + relativedelta(days=-5)
today_time = today_time.strftime("%Y-%m-%dT%H:%M:%SZ")
### enter secret and get bearer token, need to use passport for securely passing the oauth credentials, not recommended method for productive scenarios
print ("Please enter your O-auth client secret: ")
ClientSecret = '******'
ClientID = '*******'
baseUrl = "https://{0}.qualtrics.com/oauth2/token".format(dataCenter)
data = {'grant_type': 'client_credentials', 'scope': 'read:survey_responses'}
r = requests.post(baseUrl, auth=(ClientID, ClientSecret), data=data)
bearer = r.json()['access_token']
### initialize file extraction
requestCheckProgress = 0.0
progressStatus = "inProgress"
url = "https://{0}.qualtrics.com/API/v3/surveys/{1}/export-responses/".format(dataCenter, surveyId)
headers = {
"content-type": "application/json",
"authorization": "bearer " + bearer,
}
# Creating Data Export format
data = {
"format": dataFormat,
"seenUnansweredRecode": missingValues
# "startDate": today_time
}
downloadRequestResponse = requests.request("POST", url, json=data, headers=headers)
print(downloadRequestResponse.json())
try:
progressId = downloadRequestResponse.json()["result"]["progressId"]
except KeyError:
print(downloadRequestResponse.json())
sys.exit(2)
isFile = None
### trigger export file creation and wait until status is 100%
while progressStatus != "complete" and progressStatus != "failed" and isFile is None:
if isFile is None:
print ("file not ready")
else:
print ("progressStatus=", progressStatus)
requestCheckUrl = url + progressId
requestCheckResponse = requests.request("GET", requestCheckUrl, headers=headers)
try:
isFile = requestCheckResponse.json()["result"]["fileId"]
except KeyError:
1==1
print(requestCheckResponse.json())
requestCheckProgress = requestCheckResponse.json()["result"]["percentComplete"]
print("Download is " + str(requestCheckProgress) + " complete")
progressStatus = requestCheckResponse.json()["result"]["status"]
if progressStatus == "failed":
raise Exception("export failed")
fileId = requestCheckResponse.json()["result"]["fileId"]
### download file + unzip + read into dataframe + skip first two rows which contain header and column formats
requestDownloadUrl = url + fileId + '/file'
requestDownload = requests.request("GET", requestDownloadUrl, headers=headers, stream=True)
zipfile.ZipFile(io.BytesIO(requestDownload.content)).extractall("QualtricsDownloads")
df_responses = pd.read_csv('./QualtricsDownloads/' + listdir('./QualtricsDownloads/')[0])
df_responses = df_responses.iloc[2:len(df_responses.index), :]
import tempfile
# load API responce into a temporary folder and from there into a dataframe
temp_dir = tempfile.TemporaryDirectory()
requestDownloadUrl = url + fileId + '/file'
requestDownload = requests.request("GET", requestDownloadUrl, headers=headers, stream=True)
zipfile.ZipFile(io.BytesIO(requestDownload.content)).extractall(temp_dir.name)
df_responses = pd.read_csv(temp_dir.name + '/' + listdir(temp_dir.name + '/')[0]).iloc[2:len(df_responses.index), :]
df_responses = df_responses[['ResponseId','Progress','Q1','Q18','Q8_1','Q8_2','Q8_3','Q2','Q17','AccountID','ProjectID','PhaseID']]
df_responses['Q1'] = df_responses['Q1'].fillna(-9)
df_responses['Q8_1'] = df_responses['Q8_1'].fillna(-9)
df_responses['Q8_2'] = df_responses['Q8_2'].fillna(-9)
df_responses['Q8_3'] = df_responses['Q8_3'].fillna(-9)
df_responses['Q2'] = df_responses['Q2'].fillna(-9)
df_responses['Q18'] = df_responses['Q18'].fillna('')
df_responses['Q17'] = df_responses['Q17'].fillna('')
df_responses['AccountID'] = df_responses['AccountID'].fillna('')
df_responses['ProjectID'] = df_responses['ProjectID'].fillna('')
df_responses['PhaseID'] = df_responses['PhaseID'].fillna('')
from hdbcli import dbapi
from sqlalchemy import create_engine
host = "*******"
port = "****"
username = '****'
password = '******'
connection = dbapi.connect(host, port, username, password)
table_name = '"DBADMIN"."TEST_QUALTRICS"'
records = df_responses.to_records(index=False)
print(records)
def prepare_insert_statement(df, destination):
columns = df.columns
columns_string = '"' + '", "'.join(columns) + '"'
values_placeholder = ['?' for column in columns]
values_placeholder_string = ', '.join(values_placeholder)
statement = f'UPSERT {destination} ({columns_string.upper()}) VALUES ({values_placeholder_string}) WITH PRIMARY KEY'
return statement
query_template = prepare_insert_statement(df_responses, table_name)
cursor = connection.cursor()
cursor.executemany(query_template, list(records))
print("cursor closed")
cursor.close()
connection.commit()
connection.close()
Now the frontend can look like this below if you show the responses in form form of a chart in a workzone card:
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
17 | |
14 | |
13 | |
10 | |
9 | |
7 | |
7 | |
6 | |
6 | |
6 |