collaboration_client.py
Overview
`collaboration_client.py` defines a **`CollaborationClient`** class that automates login and collaboration management tasks for Qualtrics surveys, specifically tailored for the NYU Qualtrics subdomain. Its primary purpose is to:
Automate the login flow to Qualtrics using Selenium WebDriver, including handling two-factor authentication (2FA) and browser trust prompts.
Extract authenticated session cookies from the Selenium browser and use them to authorize API calls via the
requestslibrary.Provide methods to programmatically add collaborators to surveys and accept collaboration invitations via collaboration codes, using Qualtrics Collaboration API endpoints.
This file encapsulates complex UI interactions and API communication, enabling users to manage survey collaborations programmatically with minimal manual intervention.
Classes and Methods
Class: CollaborationClient
Encapsulates authentication and collaboration operations with Qualtrics.
__init__(self)
**Purpose:** Initializes the client by setting up a `requests.Session` for API communication, configuring the user-agent string, and defining the Qualtrics subdomain.
**Details:**
Uses a persistent session to maintain cookies across requests.
Sets
self.subdomain = 'nyu'to targetnyu.qualtrics.com.
**Parameters:** None
**Returns:** None
login(self) -> None
**Purpose:** Initiates the login process by prompting the user for their NYU username and password, then performing an automated Selenium-driven login.
**Details:**
Uses
input()andgetpass()for secure user credential input.Calls the internal method
_selenium_loginto execute the login flow.Prints console separators for readability.
**Parameters:** None
**Returns:** None
**Usage Example:**
client = CollaborationClient()
client.login()
add_collaborator(self, survey_id: str, collaboration_username: str) -> dict[str, str]
**Purpose:** Adds a collaborator to a specified Qualtrics survey, granting them full editing and viewing permissions.
**Details:**
Constructs the collaboration API endpoint URL using the survey ID.
Builds a detailed payload with collaborator username and a comprehensive permissions set.
Generates required headers including authentication tokens and unique request IDs.
Sends a POST request to add the collaborator.
Returns the API response text (usually JSON-formatted string).
**Parameters:**
survey_id(str): The unique identifier for the survey to which the collaborator is added.collaboration_username(str): The Qualtrics username (usually email) of the collaborator.
**Returns:**
dict[str, str](actually returns response text as a string, but annotated as dict[str, str]) — the server's response to the collaborator addition request.
**Usage Example:**
response = client.add_collaborator("SV_abc123", "[email protected]")
print(response)
enter_collaboration_code(self, code: str) -> dict[str, str]
**Purpose:** Accepts a collaboration invitation on Qualtrics by submitting a collaboration code token programmatically.
**Details:**
Sends a POST request to the collaboration invitation acceptance endpoint.
Payload is a JSON string containing the token.
Uses content-type
application/json.Returns the API response text.
**Parameters:**
code(str): The collaboration invitation token/code.
**Returns:**
dict[str, str](actually response text string) — the server's response to the collaboration code acceptance.
**Usage Example:**
response = client.enter_collaboration_code("abc123token")
print(response)
cookies(self) -> dict[str, str] (Property)
**Purpose:** Provides easy access to the current session cookies as a dictionary.
**Details:**
Converts the
requests.Sessioncookie jar to a dictionary usingrequests.utils.dict_from_cookiejar.
**Returns:**
Dictionary of cookie names to values.
_generate_qualtrics_headers(self, content_type: str) -> dict
**Purpose:** Generates the HTTP headers required for Qualtrics API requests, including security tokens and unique request identifiers.
**Details:**
Extracts the
XSRF-TOKENfrom cookies for CSRF protection.Generates fresh UUIDs for
x-request-idandx-transaction-id.Sets standard headers such as
accept,content-type,referer,origin, anduser-agent.
**Parameters:**
content_type(str): The content type of the request payload (e.g.,'application/json; charset=UTF-8').
**Returns:**
Dictionary of HTTP headers.
_selenium_login(self, nyu_username: str, nyu_password: str) -> None
**Purpose:** Automates login to Qualtrics using Selenium WebDriver, handling username/password entry, 2FA, and browser trust prompts.
**Details:**
Configures Chrome WebDriver in headless mode with custom user-agent.
Navigates to Qualtrics login page.
Waits for username and password input fields to be present.
Types credentials using
_human_typeto simulate human typing.Clicks the login button.
Waits for successful login by polling with
_at_qualtrics.Handles trust browser prompts with
_check_for_trust_browser_page.After login, extracts Selenium cookies and transfers them to the
requests.Session.Quits the Selenium driver at the end.
**Parameters:**
nyu_username(str): NYU username input by the user.nyu_password(str): NYU password input by the user.
**Returns:** None
human_sleep() -> None (Static Method)
**Purpose:** Introduces a randomized pause to simulate human-like waiting times on web pages.
**Details:**
Uses truncated normal distribution (
scipy.stats.truncnorm) to generate sleep duration between ~2 and 6 seconds, centered around 3.3 seconds.Calls
time.sleep()with the generated duration.
**Returns:** None
**Usage:** Called between key UI interactions to mimic natural user delays.
_human_type(element: WebElement, string: str) -> None (Static Method)
**Purpose:** Simulates human typing by sending characters one-by-one to a web element with varying delays.
**Details:**
For punctuation characters (
!,.,?,,), pauses longer (0.6 to 1 sec).For spaces, shorter pauses (0.14 to 0.20 sec).
For other characters, minimal pauses (0.1 to 0.13 sec).
Sends each character using
element.send_keys(char).
**Parameters:**
element(WebElement): Selenium web element representing an input field.string(str): The string to type.
**Returns:** None
_at_qualtrics(driver: webdriver) -> bool (Static Method)
**Purpose:** Checks whether the Selenium-controlled browser has successfully reached the authenticated Qualtrics landing page.
**Details:**
Looks for a known Qualtrics footer link (
<a href="http://www.qualtrics.com">).Returns
Trueif found, elseFalse.
**Parameters:**
driver(webdriver): Selenium web driver instance.
**Returns:**
Trueif at Qualtrics main page, elseFalse.
_check_for_trust_browser_page(driver: webdriver) -> bool (Static Method)
**Purpose:** Detects whether the browser trust prompt page is currently shown.
**Details:**
Checks for presence of an element with ID
'trust-browser-button'.Returns
Trueif found, elseFalse.
**Parameters:**
driver(webdriver): Selenium web driver instance.
**Returns:**
Trueif trust prompt is active, elseFalse.
Important Implementation Details and Algorithms
Selenium Headless Login with Human Emulation:
The login flow uses Selenium in headless mode with a custom user-agent string. The typing of credentials is humanized with randomized keystroke delays (_human_type), and actions are separated by randomized sleep durations (human_sleep) sampled from a truncated normal distribution to mimic human behavior and avoid bot detection.Two-Factor Authentication & Trust Prompt Handling:
After submitting credentials, the client waits in a loop until it detects either that it has arrived at the Qualtrics dashboard (_at_qualtrics) or needs to interact with a "trust browser" prompt (_check_for_trust_browser_page), which it automatically clicks. This polling loop allows the user to complete 2FA outside of automation while the script handles UI prompts.Session Cookie Transfer:
Once logged in with Selenium, the client extracts all cookies from the browser session and injects them into therequests.Sessioncookie jar. This allows subsequent API requests to be authenticated without Selenium, improving efficiency.API Request Header Generation:
For API calls (adding collaborators, accepting codes), the client generates headers dynamically. These include CSRF tokens extracted from cookies and unique identifiers (x-request-idandx-transaction-id) generated with UUIDs to comply with Qualtrics API requirements.Payload Construction for Collaborator Addition:
The payload is carefully constructed as form-encoded data with embedded JSON strings specifying collaborator status, invitation type, and detailed permissions. The permissions cover a wide range of capabilities, granting the collaborator full access to the survey.
Interaction with Other System Components
User Input Module:
Thelogin()method depends on user input (username and password) from the console.Selenium WebDriver:
Automates browser interaction for login, handling UI complexities like 2FA and trust prompts.Qualtrics Collaboration API:
The client interacts with Qualtrics backend APIs for managing survey collaborations by sending authenticated POST requests.Requests Library:
Used to send HTTP requests leveraging cookies and headers obtained after Selenium login.Session and API Request Management Layer:
The session cookie synchronization and header generation are critical for bridging UI authentication and backend API communication.
Visual Diagram: Class Structure and Key Methods
classDiagram
class CollaborationClient {
-session: requests.Session
-user_agent: str
-subdomain: str
+login()
+add_collaborator(survey_id: str, collaboration_username: str) dict[str, str]
+enter_collaboration_code(code: str) dict[str, str]
+cookies() dict[str, str]
-_generate_qualtrics_headers(content_type: str) dict
-_selenium_login(nyu_username: str, nyu_password: str) None
+human_sleep() None
-_human_type(element: WebElement, string: str) None
-_at_qualtrics(driver: webdriver) bool
-_check_for_trust_browser_page(driver: webdriver) bool
}
Summary
collaboration_client.pyprovides aCollaborationClientclass that automates Qualtrics login and collaboration management.It uses Selenium WebDriver to handle complex login flows including 2FA and browser trust prompts, simulating human interaction to avoid detection.
Authenticated session cookies are transferred from Selenium to a
requests.Sessionfor API requests.Key collaboration methods allow adding collaborators with full permissions and accepting collaboration codes.
The class dynamically generates secure request headers and carefully constructs API payloads.
This file is critical for enabling programmatic, scalable management of Qualtrics survey collaborations that cannot be achieved through simple API calls alone.
If you require further details on any method or integration with other parts of the system, please let me know!