mirror of
https://github.com/K-Dense-AI/claude-scientific-skills.git
synced 2026-01-26 16:58:56 +08:00
Add integrations
This commit is contained in:
253
scientific-integrations/labarchive-integration/SKILL.md
Normal file
253
scientific-integrations/labarchive-integration/SKILL.md
Normal file
@@ -0,0 +1,253 @@
|
||||
---
|
||||
name: labarchive-integration
|
||||
description: Toolkit for interacting with LabArchives Electronic Lab Notebook (ELN) API. This skill should be used when working with LabArchives notebooks, including authentication setup, retrieving user and notebook information, backing up notebooks, managing entries and attachments, generating reports, or integrating LabArchives with other scientific tools (Protocols.io, GraphPad Prism, SnapGene, Geneious, Jupyter, REDCap). Use this skill for any task involving programmatic access to LabArchives data or automating LabArchives workflows.
|
||||
---
|
||||
|
||||
# LabArchives Integration
|
||||
|
||||
## Overview
|
||||
|
||||
Provide comprehensive tools and workflows for interacting with the LabArchives Electronic Lab Notebook (ELN) REST API. LabArchives is a widely-used electronic lab notebook platform for research documentation, data management, and collaboration in academic and industrial laboratories.
|
||||
|
||||
This skill enables programmatic access to LabArchives notebooks, including user authentication, notebook operations, entry management, report generation, and third-party integrations.
|
||||
|
||||
## Core Capabilities
|
||||
|
||||
### 1. Authentication and Configuration
|
||||
|
||||
Set up API access credentials and regional endpoints for LabArchives API integration.
|
||||
|
||||
**Prerequisites:**
|
||||
- Enterprise LabArchives license with API access enabled
|
||||
- API access key ID and password from LabArchives administrator
|
||||
- User authentication credentials (email and external applications password)
|
||||
|
||||
**Configuration setup:**
|
||||
|
||||
Use the `scripts/setup_config.py` script to create a configuration file:
|
||||
|
||||
```bash
|
||||
python3 scripts/setup_config.py
|
||||
```
|
||||
|
||||
This creates a `config.yaml` file with the following structure:
|
||||
|
||||
```yaml
|
||||
api_url: https://api.labarchives.com/api # or regional endpoint
|
||||
access_key_id: YOUR_ACCESS_KEY_ID
|
||||
access_password: YOUR_ACCESS_PASSWORD
|
||||
```
|
||||
|
||||
**Regional API endpoints:**
|
||||
- US/International: `https://api.labarchives.com/api`
|
||||
- Australia: `https://auapi.labarchives.com/api`
|
||||
- UK: `https://ukapi.labarchives.com/api`
|
||||
|
||||
For detailed authentication instructions and troubleshooting, refer to `references/authentication_guide.md`.
|
||||
|
||||
### 2. User Information Retrieval
|
||||
|
||||
Obtain user ID (UID) and access information required for subsequent API operations.
|
||||
|
||||
**Workflow:**
|
||||
|
||||
1. Call the `users/user_access_info` API method with login credentials
|
||||
2. Parse the XML/JSON response to extract the user ID (UID)
|
||||
3. Use the UID to retrieve detailed user information via `users/user_info_via_id`
|
||||
|
||||
**Example using Python wrapper:**
|
||||
|
||||
```python
|
||||
from labarchivespy.client import Client
|
||||
|
||||
# Initialize client
|
||||
client = Client(api_url, access_key_id, access_password)
|
||||
|
||||
# Get user access info
|
||||
login_params = {'login_or_email': user_email, 'password': auth_token}
|
||||
response = client.make_call('users', 'user_access_info', params=login_params)
|
||||
|
||||
# Extract UID from response
|
||||
import xml.etree.ElementTree as ET
|
||||
uid = ET.fromstring(response.content)[0].text
|
||||
|
||||
# Get detailed user info
|
||||
params = {'uid': uid}
|
||||
user_info = client.make_call('users', 'user_info_via_id', params=params)
|
||||
```
|
||||
|
||||
### 3. Notebook Operations
|
||||
|
||||
Manage notebook access, backup, and metadata retrieval.
|
||||
|
||||
**Key operations:**
|
||||
|
||||
- **List notebooks:** Retrieve all notebooks accessible to a user
|
||||
- **Backup notebooks:** Download complete notebook data with optional attachment inclusion
|
||||
- **Get notebook IDs:** Retrieve institution-defined notebook identifiers for integration with grants/project management systems
|
||||
- **Get notebook members:** List all users with access to a specific notebook
|
||||
- **Get notebook settings:** Retrieve configuration and permissions for notebooks
|
||||
|
||||
**Notebook backup example:**
|
||||
|
||||
Use the `scripts/notebook_operations.py` script:
|
||||
|
||||
```bash
|
||||
# Backup with attachments (default, creates 7z archive)
|
||||
python3 scripts/notebook_operations.py backup --uid USER_ID --nbid NOTEBOOK_ID
|
||||
|
||||
# Backup without attachments, JSON format
|
||||
python3 scripts/notebook_operations.py backup --uid USER_ID --nbid NOTEBOOK_ID --json --no-attachments
|
||||
```
|
||||
|
||||
**API endpoint format:**
|
||||
```
|
||||
https://<api_url>/notebooks/notebook_backup?uid=<UID>&nbid=<NOTEBOOK_ID>&json=true&no_attachments=false
|
||||
```
|
||||
|
||||
For comprehensive API method documentation, refer to `references/api_reference.md`.
|
||||
|
||||
### 4. Entry and Attachment Management
|
||||
|
||||
Create, modify, and manage notebook entries and file attachments.
|
||||
|
||||
**Entry operations:**
|
||||
- Create new entries in notebooks
|
||||
- Add comments to existing entries
|
||||
- Create entry parts/components
|
||||
- Upload file attachments to entries
|
||||
|
||||
**Attachment workflow:**
|
||||
|
||||
Use the `scripts/entry_operations.py` script:
|
||||
|
||||
```bash
|
||||
# Upload attachment to an entry
|
||||
python3 scripts/entry_operations.py upload --uid USER_ID --nbid NOTEBOOK_ID --entry-id ENTRY_ID --file /path/to/file.pdf
|
||||
|
||||
# Create a new entry with text content
|
||||
python3 scripts/entry_operations.py create --uid USER_ID --nbid NOTEBOOK_ID --title "Experiment Results" --content "Results from today's experiment..."
|
||||
```
|
||||
|
||||
**Supported file types:**
|
||||
- Documents (PDF, DOCX, TXT)
|
||||
- Images (PNG, JPG, TIFF)
|
||||
- Data files (CSV, XLSX, HDF5)
|
||||
- Scientific formats (CIF, MOL, PDB)
|
||||
- Archives (ZIP, 7Z)
|
||||
|
||||
### 5. Site Reports and Analytics
|
||||
|
||||
Generate institutional reports on notebook usage, activity, and compliance (Enterprise feature).
|
||||
|
||||
**Available reports:**
|
||||
- Detailed Usage Report: User activity metrics and engagement statistics
|
||||
- Detailed Notebook Report: Notebook metadata, member lists, and settings
|
||||
- PDF/Offline Notebook Generation Report: Export tracking for compliance
|
||||
- Notebook Members Report: Access control and collaboration analytics
|
||||
- Notebook Settings Report: Configuration and permission auditing
|
||||
|
||||
**Report generation:**
|
||||
|
||||
```python
|
||||
# Generate detailed usage report
|
||||
response = client.make_call('site_reports', 'detailed_usage_report',
|
||||
params={'start_date': '2025-01-01', 'end_date': '2025-10-20'})
|
||||
```
|
||||
|
||||
### 6. Third-Party Integrations
|
||||
|
||||
LabArchives integrates with numerous scientific software platforms. This skill provides guidance on leveraging these integrations programmatically.
|
||||
|
||||
**Supported integrations:**
|
||||
- **Protocols.io:** Export protocols directly to LabArchives notebooks
|
||||
- **GraphPad Prism:** Export analyses and figures (Version 8+)
|
||||
- **SnapGene:** Direct molecular biology workflow integration
|
||||
- **Geneious:** Bioinformatics analysis export
|
||||
- **Jupyter:** Embed Jupyter notebooks as entries
|
||||
- **REDCap:** Clinical data capture integration
|
||||
- **Qeios:** Research publishing platform
|
||||
- **SciSpace:** Literature management
|
||||
|
||||
**OAuth authentication:**
|
||||
LabArchives now uses OAuth for all new integrations. Legacy integrations may use API key authentication.
|
||||
|
||||
For detailed integration setup instructions and use cases, refer to `references/integrations.md`.
|
||||
|
||||
## Common Workflows
|
||||
|
||||
### Complete notebook backup workflow
|
||||
|
||||
1. Authenticate and obtain user ID
|
||||
2. List all accessible notebooks
|
||||
3. Iterate through notebooks and backup each one
|
||||
4. Store backups with timestamp metadata
|
||||
|
||||
```bash
|
||||
# Complete backup script
|
||||
python3 scripts/notebook_operations.py backup-all --email user@example.edu --password AUTH_TOKEN
|
||||
```
|
||||
|
||||
### Automated data upload workflow
|
||||
|
||||
1. Authenticate with LabArchives API
|
||||
2. Identify target notebook and entry
|
||||
3. Upload experimental data files
|
||||
4. Add metadata comments to entries
|
||||
5. Generate activity report
|
||||
|
||||
### Integration workflow example (Jupyter → LabArchives)
|
||||
|
||||
1. Export Jupyter notebook to HTML or PDF
|
||||
2. Use entry_operations.py to upload to LabArchives
|
||||
3. Add comment with execution timestamp and environment info
|
||||
4. Tag entry for easy retrieval
|
||||
|
||||
## Python Package Installation
|
||||
|
||||
Install the `labarchives-py` wrapper for simplified API access:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/mcmero/labarchives-py
|
||||
cd labarchives-py
|
||||
pip install .
|
||||
```
|
||||
|
||||
Alternatively, use direct HTTP requests via Python's `requests` library for custom implementations.
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Rate limiting:** Implement appropriate delays between API calls to avoid throttling
|
||||
2. **Error handling:** Always wrap API calls in try-except blocks with appropriate logging
|
||||
3. **Authentication security:** Store credentials in environment variables or secure config files (never in code)
|
||||
4. **Backup verification:** After notebook backup, verify file integrity and completeness
|
||||
5. **Incremental operations:** For large notebooks, use pagination and batch processing
|
||||
6. **Regional endpoints:** Use the correct regional API endpoint for optimal performance
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Common issues:**
|
||||
|
||||
- **401 Unauthorized:** Verify access key ID and password are correct; check API access is enabled for your account
|
||||
- **404 Not Found:** Confirm notebook ID (nbid) exists and user has access permissions
|
||||
- **403 Forbidden:** Check user permissions for the requested operation
|
||||
- **Empty response:** Ensure required parameters (uid, nbid) are provided correctly
|
||||
- **Attachment upload failures:** Verify file size limits and format compatibility
|
||||
|
||||
For additional support, contact LabArchives at support@labarchives.com.
|
||||
|
||||
## Resources
|
||||
|
||||
This skill includes bundled resources to support LabArchives API integration:
|
||||
|
||||
### scripts/
|
||||
|
||||
- `setup_config.py`: Interactive configuration file generator for API credentials
|
||||
- `notebook_operations.py`: Utilities for listing, backing up, and managing notebooks
|
||||
- `entry_operations.py`: Tools for creating entries and uploading attachments
|
||||
|
||||
### references/
|
||||
|
||||
- `api_reference.md`: Comprehensive API endpoint documentation with parameters and examples
|
||||
- `authentication_guide.md`: Detailed authentication setup and configuration instructions
|
||||
- `integrations.md`: Third-party integration setup guides and use cases
|
||||
@@ -0,0 +1,342 @@
|
||||
# LabArchives API Reference
|
||||
|
||||
## API Structure
|
||||
|
||||
All LabArchives API calls follow this URL pattern:
|
||||
|
||||
```
|
||||
https://<base_url>/api/<api_class>/<api_method>?<authentication_parameters>&<method_parameters>
|
||||
```
|
||||
|
||||
## Regional API Endpoints
|
||||
|
||||
| Region | Base URL |
|
||||
|--------|----------|
|
||||
| US/International | `https://api.labarchives.com/api` |
|
||||
| Australia | `https://auapi.labarchives.com/api` |
|
||||
| UK | `https://ukapi.labarchives.com/api` |
|
||||
|
||||
## Authentication
|
||||
|
||||
All API calls require authentication parameters:
|
||||
|
||||
- `access_key_id`: Provided by LabArchives administrator
|
||||
- `access_password`: Provided by LabArchives administrator
|
||||
- Additional user-specific credentials may be required for certain operations
|
||||
|
||||
## API Classes and Methods
|
||||
|
||||
### Users API Class
|
||||
|
||||
#### `users/user_access_info`
|
||||
|
||||
Retrieve user ID and notebook access information.
|
||||
|
||||
**Parameters:**
|
||||
- `login_or_email` (required): User's email address or login username
|
||||
- `password` (required): User's external applications password (not regular login password)
|
||||
|
||||
**Returns:** XML or JSON response containing:
|
||||
- User ID (uid)
|
||||
- List of accessible notebooks with IDs (nbid)
|
||||
- Account status and permissions
|
||||
|
||||
**Example:**
|
||||
```python
|
||||
params = {
|
||||
'login_or_email': 'researcher@university.edu',
|
||||
'password': 'external_app_password'
|
||||
}
|
||||
response = client.make_call('users', 'user_access_info', params=params)
|
||||
```
|
||||
|
||||
#### `users/user_info_via_id`
|
||||
|
||||
Retrieve detailed user information by user ID.
|
||||
|
||||
**Parameters:**
|
||||
- `uid` (required): User ID obtained from user_access_info
|
||||
|
||||
**Returns:** User profile information including:
|
||||
- Name and email
|
||||
- Account creation date
|
||||
- Institution affiliation
|
||||
- Role and permissions
|
||||
- Storage quota and usage
|
||||
|
||||
**Example:**
|
||||
```python
|
||||
params = {'uid': '12345'}
|
||||
response = client.make_call('users', 'user_info_via_id', params=params)
|
||||
```
|
||||
|
||||
### Notebooks API Class
|
||||
|
||||
#### `notebooks/notebook_backup`
|
||||
|
||||
Download complete notebook data including entries, attachments, and metadata.
|
||||
|
||||
**Parameters:**
|
||||
- `uid` (required): User ID
|
||||
- `nbid` (required): Notebook ID
|
||||
- `json` (optional, default: false): Return data in JSON format instead of XML
|
||||
- `no_attachments` (optional, default: false): Exclude attachments from backup
|
||||
|
||||
**Returns:**
|
||||
- When `no_attachments=false`: 7z compressed archive containing all notebook data
|
||||
- When `no_attachments=true`: XML or JSON structured data with entry content
|
||||
|
||||
**File format:**
|
||||
The returned archive includes:
|
||||
- Entry text content in HTML format
|
||||
- File attachments in original formats
|
||||
- Metadata XML files with timestamps, authors, and version history
|
||||
- Comment threads and annotations
|
||||
|
||||
**Example:**
|
||||
```python
|
||||
# Full backup with attachments
|
||||
params = {
|
||||
'uid': '12345',
|
||||
'nbid': '67890',
|
||||
'json': 'false',
|
||||
'no_attachments': 'false'
|
||||
}
|
||||
response = client.make_call('notebooks', 'notebook_backup', params=params)
|
||||
|
||||
# Write to file
|
||||
with open('notebook_backup.7z', 'wb') as f:
|
||||
f.write(response.content)
|
||||
```
|
||||
|
||||
```python
|
||||
# Metadata only backup (JSON format, no attachments)
|
||||
params = {
|
||||
'uid': '12345',
|
||||
'nbid': '67890',
|
||||
'json': 'true',
|
||||
'no_attachments': 'true'
|
||||
}
|
||||
response = client.make_call('notebooks', 'notebook_backup', params=params)
|
||||
import json
|
||||
notebook_data = json.loads(response.content)
|
||||
```
|
||||
|
||||
#### `notebooks/list_notebooks`
|
||||
|
||||
Retrieve all notebooks accessible to a user (method name may vary by API version).
|
||||
|
||||
**Parameters:**
|
||||
- `uid` (required): User ID
|
||||
|
||||
**Returns:** List of notebooks with:
|
||||
- Notebook ID (nbid)
|
||||
- Notebook name
|
||||
- Creation and modification dates
|
||||
- Access level (owner, editor, viewer)
|
||||
- Member count
|
||||
|
||||
### Entries API Class
|
||||
|
||||
#### `entries/create_entry`
|
||||
|
||||
Create a new entry in a notebook.
|
||||
|
||||
**Parameters:**
|
||||
- `uid` (required): User ID
|
||||
- `nbid` (required): Notebook ID
|
||||
- `title` (required): Entry title
|
||||
- `content` (optional): HTML-formatted entry content
|
||||
- `date` (optional): Entry date (defaults to current date)
|
||||
|
||||
**Returns:** Entry ID and creation confirmation
|
||||
|
||||
**Example:**
|
||||
```python
|
||||
params = {
|
||||
'uid': '12345',
|
||||
'nbid': '67890',
|
||||
'title': 'Experiment 2025-10-20',
|
||||
'content': '<p>Conducted PCR amplification of target gene...</p>',
|
||||
'date': '2025-10-20'
|
||||
}
|
||||
response = client.make_call('entries', 'create_entry', params=params)
|
||||
```
|
||||
|
||||
#### `entries/create_comment`
|
||||
|
||||
Add a comment to an existing entry.
|
||||
|
||||
**Parameters:**
|
||||
- `uid` (required): User ID
|
||||
- `nbid` (required): Notebook ID
|
||||
- `entry_id` (required): Target entry ID
|
||||
- `comment` (required): Comment text (HTML supported)
|
||||
|
||||
**Returns:** Comment ID and timestamp
|
||||
|
||||
#### `entries/create_part`
|
||||
|
||||
Add a component/part to an entry (e.g., text section, table, image).
|
||||
|
||||
**Parameters:**
|
||||
- `uid` (required): User ID
|
||||
- `nbid` (required): Notebook ID
|
||||
- `entry_id` (required): Target entry ID
|
||||
- `part_type` (required): Type of part (text, table, image, etc.)
|
||||
- `content` (required): Part content in appropriate format
|
||||
|
||||
**Returns:** Part ID and creation confirmation
|
||||
|
||||
#### `entries/upload_attachment`
|
||||
|
||||
Upload a file attachment to an entry.
|
||||
|
||||
**Parameters:**
|
||||
- `uid` (required): User ID
|
||||
- `nbid` (required): Notebook ID
|
||||
- `entry_id` (required): Target entry ID
|
||||
- `file` (required): File data (multipart/form-data)
|
||||
- `filename` (required): Original filename
|
||||
|
||||
**Returns:** Attachment ID and upload confirmation
|
||||
|
||||
**Example using requests library:**
|
||||
```python
|
||||
import requests
|
||||
|
||||
url = f'{api_url}/entries/upload_attachment'
|
||||
files = {'file': open('/path/to/data.csv', 'rb')}
|
||||
params = {
|
||||
'uid': '12345',
|
||||
'nbid': '67890',
|
||||
'entry_id': '11111',
|
||||
'filename': 'data.csv',
|
||||
'access_key_id': access_key_id,
|
||||
'access_password': access_password
|
||||
}
|
||||
response = requests.post(url, files=files, data=params)
|
||||
```
|
||||
|
||||
### Site Reports API Class
|
||||
|
||||
Enterprise-only features for institutional reporting and analytics.
|
||||
|
||||
#### `site_reports/detailed_usage_report`
|
||||
|
||||
Generate comprehensive usage statistics for the institution.
|
||||
|
||||
**Parameters:**
|
||||
- `start_date` (required): Report start date (YYYY-MM-DD)
|
||||
- `end_date` (required): Report end date (YYYY-MM-DD)
|
||||
- `format` (optional): Output format (csv, json, xml)
|
||||
|
||||
**Returns:** Usage metrics including:
|
||||
- User login frequency
|
||||
- Entry creation counts
|
||||
- Storage utilization
|
||||
- Collaboration statistics
|
||||
- Time-based activity patterns
|
||||
|
||||
#### `site_reports/detailed_notebook_report`
|
||||
|
||||
Generate detailed report on all notebooks in the institution.
|
||||
|
||||
**Parameters:**
|
||||
- `include_settings` (optional, default: false): Include notebook settings
|
||||
- `include_members` (optional, default: false): Include member lists
|
||||
|
||||
**Returns:** Notebook inventory with:
|
||||
- Notebook names and IDs
|
||||
- Owner information
|
||||
- Creation and last modified dates
|
||||
- Member count and access levels
|
||||
- Storage size
|
||||
- Settings (if requested)
|
||||
|
||||
#### `site_reports/pdf_offline_generation_report`
|
||||
|
||||
Track PDF exports for compliance and auditing purposes.
|
||||
|
||||
**Parameters:**
|
||||
- `start_date` (required): Report start date
|
||||
- `end_date` (required): Report end date
|
||||
|
||||
**Returns:** Export activity log with:
|
||||
- User who generated PDF
|
||||
- Notebook and entry exported
|
||||
- Export timestamp
|
||||
- IP address
|
||||
|
||||
### Utilities API Class
|
||||
|
||||
#### `utilities/institutional_login_urls`
|
||||
|
||||
Retrieve institutional login URLs for SSO integration.
|
||||
|
||||
**Parameters:** None required (uses access key authentication)
|
||||
|
||||
**Returns:** List of institutional login endpoints
|
||||
|
||||
## Response Formats
|
||||
|
||||
### XML Response Example
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<response>
|
||||
<uid>12345</uid>
|
||||
<email>researcher@university.edu</email>
|
||||
<notebooks>
|
||||
<notebook>
|
||||
<nbid>67890</nbid>
|
||||
<name>Lab Notebook 2025</name>
|
||||
<role>owner</role>
|
||||
</notebook>
|
||||
</notebooks>
|
||||
</response>
|
||||
```
|
||||
|
||||
### JSON Response Example
|
||||
|
||||
```json
|
||||
{
|
||||
"uid": "12345",
|
||||
"email": "researcher@university.edu",
|
||||
"notebooks": [
|
||||
{
|
||||
"nbid": "67890",
|
||||
"name": "Lab Notebook 2025",
|
||||
"role": "owner"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Error Codes
|
||||
|
||||
| Code | Message | Meaning | Solution |
|
||||
|------|---------|---------|----------|
|
||||
| 401 | Unauthorized | Invalid credentials | Verify access_key_id and access_password |
|
||||
| 403 | Forbidden | Insufficient permissions | Check user role and notebook access |
|
||||
| 404 | Not Found | Resource doesn't exist | Verify uid, nbid, or entry_id are correct |
|
||||
| 429 | Too Many Requests | Rate limit exceeded | Implement exponential backoff |
|
||||
| 500 | Internal Server Error | Server-side issue | Retry request or contact support |
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
LabArchives implements rate limiting to ensure service stability:
|
||||
|
||||
- **Recommended:** Maximum 60 requests per minute per API key
|
||||
- **Burst allowance:** Short bursts up to 100 requests may be tolerated
|
||||
- **Best practice:** Implement 1-2 second delays between requests for batch operations
|
||||
|
||||
## API Versioning
|
||||
|
||||
LabArchives API is backward compatible. New methods are added without breaking existing implementations. Monitor LabArchives announcements for new capabilities.
|
||||
|
||||
## Support and Documentation
|
||||
|
||||
For API access requests, technical questions, or feature requests:
|
||||
- Email: support@labarchives.com
|
||||
- Include your institution name and specific use case for faster assistance
|
||||
@@ -0,0 +1,357 @@
|
||||
# LabArchives Authentication Guide
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### 1. Enterprise License
|
||||
|
||||
API access requires an Enterprise LabArchives license. Contact your LabArchives administrator or sales@labarchives.com to:
|
||||
- Verify your institution has Enterprise access
|
||||
- Request API access enablement for your account
|
||||
- Obtain institutional API credentials
|
||||
|
||||
### 2. API Credentials
|
||||
|
||||
You need two sets of credentials:
|
||||
|
||||
#### Institutional API Credentials (from LabArchives administrator)
|
||||
- **Access Key ID**: Institution-level identifier
|
||||
- **Access Password**: Institution-level secret
|
||||
|
||||
#### User Authentication Credentials (self-configured)
|
||||
- **Email**: Your LabArchives account email (e.g., researcher@university.edu)
|
||||
- **External Applications Password**: Set in your LabArchives account settings
|
||||
|
||||
## Setting Up External Applications Password
|
||||
|
||||
The external applications password is different from your regular LabArchives login password. It provides API access without exposing your primary credentials.
|
||||
|
||||
**Steps to create external applications password:**
|
||||
|
||||
1. Log into your LabArchives account at mynotebook.labarchives.com (or your institutional URL)
|
||||
2. Navigate to **Account Settings** (click your name in top-right corner)
|
||||
3. Select **Security & Privacy** tab
|
||||
4. Find **External Applications** section
|
||||
5. Click **Generate New Password** or **Reset Password**
|
||||
6. Copy and securely store this password (you won't see it again)
|
||||
7. Use this password for all API authentication
|
||||
|
||||
**Security note:** Treat this password like an API token. If compromised, regenerate it immediately from account settings.
|
||||
|
||||
## Configuration File Setup
|
||||
|
||||
Create a `config.yaml` file to store your credentials securely:
|
||||
|
||||
```yaml
|
||||
# Regional API endpoint
|
||||
api_url: https://api.labarchives.com/api
|
||||
|
||||
# Institutional credentials (from administrator)
|
||||
access_key_id: YOUR_ACCESS_KEY_ID_HERE
|
||||
access_password: YOUR_ACCESS_PASSWORD_HERE
|
||||
|
||||
# User credentials (for user-specific operations)
|
||||
user_email: researcher@university.edu
|
||||
user_external_password: YOUR_EXTERNAL_APP_PASSWORD_HERE
|
||||
```
|
||||
|
||||
**Alternative: Environment variables**
|
||||
|
||||
For enhanced security, use environment variables instead of config file:
|
||||
|
||||
```bash
|
||||
export LABARCHIVES_API_URL="https://api.labarchives.com/api"
|
||||
export LABARCHIVES_ACCESS_KEY_ID="your_key_id"
|
||||
export LABARCHIVES_ACCESS_PASSWORD="your_access_password"
|
||||
export LABARCHIVES_USER_EMAIL="researcher@university.edu"
|
||||
export LABARCHIVES_USER_PASSWORD="your_external_app_password"
|
||||
```
|
||||
|
||||
## Regional Endpoints
|
||||
|
||||
Select the correct regional API endpoint for your institution:
|
||||
|
||||
| Region | Endpoint | Use if your LabArchives URL is |
|
||||
|--------|----------|--------------------------------|
|
||||
| US/International | `https://api.labarchives.com/api` | `mynotebook.labarchives.com` |
|
||||
| Australia | `https://auapi.labarchives.com/api` | `aunotebook.labarchives.com` |
|
||||
| UK | `https://ukapi.labarchives.com/api` | `uknotebook.labarchives.com` |
|
||||
|
||||
Using the wrong regional endpoint will result in authentication failures even with correct credentials.
|
||||
|
||||
## Authentication Flow
|
||||
|
||||
### Option 1: Using labarchives-py Python Wrapper
|
||||
|
||||
```python
|
||||
from labarchivespy.client import Client
|
||||
import yaml
|
||||
|
||||
# Load configuration
|
||||
with open('config.yaml', 'r') as f:
|
||||
config = yaml.safe_load(f)
|
||||
|
||||
# Initialize client with institutional credentials
|
||||
client = Client(
|
||||
config['api_url'],
|
||||
config['access_key_id'],
|
||||
config['access_password']
|
||||
)
|
||||
|
||||
# Authenticate as specific user to get UID
|
||||
login_params = {
|
||||
'login_or_email': config['user_email'],
|
||||
'password': config['user_external_password']
|
||||
}
|
||||
response = client.make_call('users', 'user_access_info', params=login_params)
|
||||
|
||||
# Parse response to extract UID
|
||||
import xml.etree.ElementTree as ET
|
||||
uid = ET.fromstring(response.content)[0].text
|
||||
print(f"Authenticated as user ID: {uid}")
|
||||
```
|
||||
|
||||
### Option 2: Direct HTTP Requests with Python requests
|
||||
|
||||
```python
|
||||
import requests
|
||||
import yaml
|
||||
|
||||
# Load configuration
|
||||
with open('config.yaml', 'r') as f:
|
||||
config = yaml.safe_load(f)
|
||||
|
||||
# Construct API call
|
||||
url = f"{config['api_url']}/users/user_access_info"
|
||||
params = {
|
||||
'access_key_id': config['access_key_id'],
|
||||
'access_password': config['access_password'],
|
||||
'login_or_email': config['user_email'],
|
||||
'password': config['user_external_password']
|
||||
}
|
||||
|
||||
# Make authenticated request
|
||||
response = requests.get(url, params=params)
|
||||
|
||||
if response.status_code == 200:
|
||||
print("Authentication successful!")
|
||||
print(response.content.decode('utf-8'))
|
||||
else:
|
||||
print(f"Authentication failed: {response.status_code}")
|
||||
print(response.content.decode('utf-8'))
|
||||
```
|
||||
|
||||
### Option 3: Using R
|
||||
|
||||
```r
|
||||
library(httr)
|
||||
library(xml2)
|
||||
|
||||
# Configuration
|
||||
api_url <- "https://api.labarchives.com/api"
|
||||
access_key_id <- "YOUR_ACCESS_KEY_ID"
|
||||
access_password <- "YOUR_ACCESS_PASSWORD"
|
||||
user_email <- "researcher@university.edu"
|
||||
user_external_password <- "YOUR_EXTERNAL_APP_PASSWORD"
|
||||
|
||||
# Make authenticated request
|
||||
response <- GET(
|
||||
paste0(api_url, "/users/user_access_info"),
|
||||
query = list(
|
||||
access_key_id = access_key_id,
|
||||
access_password = access_password,
|
||||
login_or_email = user_email,
|
||||
password = user_external_password
|
||||
)
|
||||
)
|
||||
|
||||
# Parse response
|
||||
if (status_code(response) == 200) {
|
||||
content <- content(response, as = "text", encoding = "UTF-8")
|
||||
xml_data <- read_xml(content)
|
||||
uid <- xml_text(xml_find_first(xml_data, "//uid"))
|
||||
print(paste("Authenticated as user ID:", uid))
|
||||
} else {
|
||||
print(paste("Authentication failed:", status_code(response)))
|
||||
}
|
||||
```
|
||||
|
||||
## OAuth Authentication (New Integrations)
|
||||
|
||||
LabArchives now uses OAuth 2.0 for new third-party integrations. Legacy API key authentication (described above) continues to work for direct API access.
|
||||
|
||||
**OAuth flow (for app developers):**
|
||||
|
||||
1. Register your application with LabArchives
|
||||
2. Obtain client ID and client secret
|
||||
3. Implement OAuth 2.0 authorization code flow
|
||||
4. Exchange authorization code for access token
|
||||
5. Use access token for API requests
|
||||
|
||||
Contact LabArchives developer support for OAuth integration documentation.
|
||||
|
||||
## Troubleshooting Authentication Issues
|
||||
|
||||
### 401 Unauthorized Error
|
||||
|
||||
**Possible causes and solutions:**
|
||||
|
||||
1. **Incorrect access_key_id or access_password**
|
||||
- Verify credentials with your LabArchives administrator
|
||||
- Check for typos or extra whitespace in config file
|
||||
|
||||
2. **Wrong external applications password**
|
||||
- Confirm you're using the external applications password, not your regular login password
|
||||
- Regenerate external applications password in account settings
|
||||
|
||||
3. **API access not enabled**
|
||||
- Contact your LabArchives administrator to enable API access for your account
|
||||
- Verify your institution has Enterprise license
|
||||
|
||||
4. **Wrong regional endpoint**
|
||||
- Confirm your api_url matches your institution's LabArchives instance
|
||||
- Check if you're using .com, .auapi, or .ukapi domain
|
||||
|
||||
### 403 Forbidden Error
|
||||
|
||||
**Possible causes and solutions:**
|
||||
|
||||
1. **Insufficient permissions**
|
||||
- Verify your account role has necessary permissions
|
||||
- Check if you have access to the specific notebook (nbid)
|
||||
|
||||
2. **Account suspended or expired**
|
||||
- Contact your LabArchives administrator to check account status
|
||||
|
||||
### Network and Connection Issues
|
||||
|
||||
**Firewall/proxy configuration:**
|
||||
|
||||
If your institution uses a firewall or proxy:
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
# Configure proxy
|
||||
proxies = {
|
||||
'http': 'http://proxy.university.edu:8080',
|
||||
'https': 'http://proxy.university.edu:8080'
|
||||
}
|
||||
|
||||
# Make request with proxy
|
||||
response = requests.get(url, params=params, proxies=proxies)
|
||||
```
|
||||
|
||||
**SSL certificate verification:**
|
||||
|
||||
For self-signed certificates (not recommended for production):
|
||||
|
||||
```python
|
||||
# Disable SSL verification (use only for testing)
|
||||
response = requests.get(url, params=params, verify=False)
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Never commit credentials to version control**
|
||||
- Add `config.yaml` to `.gitignore`
|
||||
- Use environment variables or secret management systems
|
||||
|
||||
2. **Rotate credentials regularly**
|
||||
- Change external applications password every 90 days
|
||||
- Regenerate API keys annually
|
||||
|
||||
3. **Use least privilege principle**
|
||||
- Request only necessary API permissions
|
||||
- Create separate API credentials for different applications
|
||||
|
||||
4. **Monitor API usage**
|
||||
- Regularly review API access logs
|
||||
- Set up alerts for unusual activity
|
||||
|
||||
5. **Secure storage**
|
||||
- Encrypt configuration files at rest
|
||||
- Use system keychain or secret management tools (e.g., AWS Secrets Manager, Azure Key Vault)
|
||||
|
||||
## Testing Authentication
|
||||
|
||||
Use this script to verify your authentication setup:
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
"""Test LabArchives API authentication"""
|
||||
|
||||
from labarchivespy.client import Client
|
||||
import yaml
|
||||
import sys
|
||||
|
||||
def test_authentication():
|
||||
try:
|
||||
# Load config
|
||||
with open('config.yaml', 'r') as f:
|
||||
config = yaml.safe_load(f)
|
||||
|
||||
print("Configuration loaded successfully")
|
||||
print(f"API URL: {config['api_url']}")
|
||||
|
||||
# Initialize client
|
||||
client = Client(
|
||||
config['api_url'],
|
||||
config['access_key_id'],
|
||||
config['access_password']
|
||||
)
|
||||
print("Client initialized")
|
||||
|
||||
# Test authentication
|
||||
login_params = {
|
||||
'login_or_email': config['user_email'],
|
||||
'password': config['user_external_password']
|
||||
}
|
||||
response = client.make_call('users', 'user_access_info', params=login_params)
|
||||
|
||||
if response.status_code == 200:
|
||||
print("✅ Authentication successful!")
|
||||
|
||||
# Extract UID
|
||||
import xml.etree.ElementTree as ET
|
||||
uid = ET.fromstring(response.content)[0].text
|
||||
print(f"User ID: {uid}")
|
||||
|
||||
# Get user info
|
||||
user_response = client.make_call('users', 'user_info_via_id', params={'uid': uid})
|
||||
print("✅ User information retrieved successfully")
|
||||
|
||||
return True
|
||||
else:
|
||||
print(f"❌ Authentication failed: {response.status_code}")
|
||||
print(response.content.decode('utf-8'))
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error: {str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
if __name__ == '__main__':
|
||||
success = test_authentication()
|
||||
sys.exit(0 if success else 1)
|
||||
```
|
||||
|
||||
Run this script to confirm everything is configured correctly:
|
||||
|
||||
```bash
|
||||
python3 test_auth.py
|
||||
```
|
||||
|
||||
## Getting Help
|
||||
|
||||
If authentication continues to fail after troubleshooting:
|
||||
|
||||
1. Contact your institutional LabArchives administrator
|
||||
2. Email LabArchives support: support@labarchives.com
|
||||
3. Include:
|
||||
- Your institution name
|
||||
- Your LabArchives account email
|
||||
- Error messages and response codes
|
||||
- Regional endpoint you're using
|
||||
- Programming language and library versions
|
||||
@@ -0,0 +1,425 @@
|
||||
# LabArchives Third-Party Integrations
|
||||
|
||||
## Overview
|
||||
|
||||
LabArchives integrates with numerous scientific software platforms to streamline research workflows. This document covers programmatic integration approaches, automation strategies, and best practices for each supported platform.
|
||||
|
||||
## Integration Categories
|
||||
|
||||
### 1. Protocol Management
|
||||
|
||||
#### Protocols.io Integration
|
||||
|
||||
Export protocols directly from Protocols.io to LabArchives notebooks.
|
||||
|
||||
**Use cases:**
|
||||
- Standardize experimental procedures across lab notebooks
|
||||
- Maintain version control for protocols
|
||||
- Link protocols to experimental results
|
||||
|
||||
**Setup:**
|
||||
1. Enable Protocols.io integration in LabArchives settings
|
||||
2. Authenticate with Protocols.io account
|
||||
3. Browse and select protocols to export
|
||||
|
||||
**Programmatic approach:**
|
||||
```python
|
||||
# Export Protocols.io protocol as HTML/PDF
|
||||
# Then upload to LabArchives via API
|
||||
|
||||
def import_protocol_to_labarchives(client, uid, nbid, protocol_id):
|
||||
"""Import Protocols.io protocol to LabArchives entry"""
|
||||
# 1. Fetch protocol from Protocols.io API
|
||||
protocol_data = fetch_protocol_from_protocolsio(protocol_id)
|
||||
|
||||
# 2. Create new entry in LabArchives
|
||||
entry_params = {
|
||||
'uid': uid,
|
||||
'nbid': nbid,
|
||||
'title': f"Protocol: {protocol_data['title']}",
|
||||
'content': protocol_data['html_content']
|
||||
}
|
||||
response = client.make_call('entries', 'create_entry', params=entry_params)
|
||||
|
||||
# 3. Add protocol metadata as comment
|
||||
entry_id = extract_entry_id(response)
|
||||
comment_params = {
|
||||
'uid': uid,
|
||||
'nbid': nbid,
|
||||
'entry_id': entry_id,
|
||||
'comment': f"Protocols.io ID: {protocol_id}<br>Version: {protocol_data['version']}"
|
||||
}
|
||||
client.make_call('entries', 'create_comment', params=comment_params)
|
||||
|
||||
return entry_id
|
||||
```
|
||||
|
||||
**Updated:** September 22, 2025
|
||||
|
||||
### 2. Data Analysis Tools
|
||||
|
||||
#### GraphPad Prism Integration (Version 8+)
|
||||
|
||||
Export analyses, graphs, and figures directly from Prism to LabArchives.
|
||||
|
||||
**Use cases:**
|
||||
- Archive statistical analyses with raw data
|
||||
- Document figure generation for publications
|
||||
- Maintain analysis audit trail for compliance
|
||||
|
||||
**Setup:**
|
||||
1. Install GraphPad Prism 8 or higher
|
||||
2. Configure LabArchives connection in Prism preferences
|
||||
3. Use "Export to LabArchives" option from File menu
|
||||
|
||||
**Programmatic approach:**
|
||||
```python
|
||||
# Upload Prism files to LabArchives via API
|
||||
|
||||
def upload_prism_analysis(client, uid, nbid, entry_id, prism_file_path):
|
||||
"""Upload GraphPad Prism file to LabArchives entry"""
|
||||
import requests
|
||||
|
||||
url = f'{client.api_url}/entries/upload_attachment'
|
||||
files = {'file': open(prism_file_path, 'rb')}
|
||||
params = {
|
||||
'uid': uid,
|
||||
'nbid': nbid,
|
||||
'entry_id': entry_id,
|
||||
'filename': os.path.basename(prism_file_path),
|
||||
'access_key_id': client.access_key_id,
|
||||
'access_password': client.access_password
|
||||
}
|
||||
|
||||
response = requests.post(url, files=files, data=params)
|
||||
return response
|
||||
```
|
||||
|
||||
**Supported file types:**
|
||||
- .pzfx (Prism project files)
|
||||
- .png, .jpg, .pdf (exported graphs)
|
||||
- .xlsx (exported data tables)
|
||||
|
||||
**Updated:** September 8, 2025
|
||||
|
||||
### 3. Molecular Biology & Bioinformatics
|
||||
|
||||
#### SnapGene Integration
|
||||
|
||||
Direct integration for molecular biology workflows, plasmid maps, and sequence analysis.
|
||||
|
||||
**Use cases:**
|
||||
- Document cloning strategies
|
||||
- Archive plasmid maps with experimental records
|
||||
- Link sequences to experimental results
|
||||
|
||||
**Setup:**
|
||||
1. Install SnapGene software
|
||||
2. Enable LabArchives export in SnapGene preferences
|
||||
3. Use "Send to LabArchives" feature
|
||||
|
||||
**File format support:**
|
||||
- .dna (SnapGene files)
|
||||
- .gb, .gbk (GenBank format)
|
||||
- .fasta (sequence files)
|
||||
- .png, .pdf (plasmid map exports)
|
||||
|
||||
**Programmatic workflow:**
|
||||
```python
|
||||
def upload_snapgene_file(client, uid, nbid, entry_id, snapgene_file):
|
||||
"""Upload SnapGene file with preview image"""
|
||||
# Upload main SnapGene file
|
||||
upload_attachment(client, uid, nbid, entry_id, snapgene_file)
|
||||
|
||||
# Generate and upload preview image (requires SnapGene CLI)
|
||||
preview_png = generate_snapgene_preview(snapgene_file)
|
||||
upload_attachment(client, uid, nbid, entry_id, preview_png)
|
||||
```
|
||||
|
||||
#### Geneious Integration
|
||||
|
||||
Bioinformatics analysis export from Geneious to LabArchives.
|
||||
|
||||
**Use cases:**
|
||||
- Archive sequence alignments and phylogenetic trees
|
||||
- Document NGS analysis pipelines
|
||||
- Link bioinformatics workflows to wet-lab experiments
|
||||
|
||||
**Supported exports:**
|
||||
- Sequence alignments
|
||||
- Phylogenetic trees
|
||||
- Assembly reports
|
||||
- Variant calling results
|
||||
|
||||
**File formats:**
|
||||
- .geneious (Geneious documents)
|
||||
- .fasta, .fastq (sequence data)
|
||||
- .bam, .sam (alignment files)
|
||||
- .vcf (variant files)
|
||||
|
||||
### 4. Computational Notebooks
|
||||
|
||||
#### Jupyter Integration
|
||||
|
||||
Embed Jupyter notebooks as LabArchives entries for reproducible computational research.
|
||||
|
||||
**Use cases:**
|
||||
- Document data analysis workflows
|
||||
- Archive computational experiments
|
||||
- Link code, results, and narrative
|
||||
|
||||
**Workflow:**
|
||||
|
||||
```python
|
||||
def export_jupyter_to_labarchives(notebook_path, client, uid, nbid):
|
||||
"""Export Jupyter notebook to LabArchives"""
|
||||
import nbformat
|
||||
from nbconvert import HTMLExporter
|
||||
|
||||
# Load notebook
|
||||
with open(notebook_path, 'r') as f:
|
||||
nb = nbformat.read(f, as_version=4)
|
||||
|
||||
# Convert to HTML
|
||||
html_exporter = HTMLExporter()
|
||||
html_exporter.template_name = 'classic'
|
||||
(body, resources) = html_exporter.from_notebook_node(nb)
|
||||
|
||||
# Create entry in LabArchives
|
||||
entry_params = {
|
||||
'uid': uid,
|
||||
'nbid': nbid,
|
||||
'title': f"Jupyter Notebook: {os.path.basename(notebook_path)}",
|
||||
'content': body
|
||||
}
|
||||
response = client.make_call('entries', 'create_entry', params=entry_params)
|
||||
|
||||
# Upload original .ipynb file as attachment
|
||||
entry_id = extract_entry_id(response)
|
||||
upload_attachment(client, uid, nbid, entry_id, notebook_path)
|
||||
|
||||
return entry_id
|
||||
```
|
||||
|
||||
**Best practices:**
|
||||
- Export with outputs included (Run All Cells before export)
|
||||
- Include environment.yml or requirements.txt as attachment
|
||||
- Add execution timestamp and system info in comments
|
||||
|
||||
### 5. Clinical Research
|
||||
|
||||
#### REDCap Integration
|
||||
|
||||
Clinical data capture integration with LabArchives for research compliance and audit trails.
|
||||
|
||||
**Use cases:**
|
||||
- Link clinical data collection to research notebooks
|
||||
- Maintain audit trails for regulatory compliance
|
||||
- Document clinical trial protocols and amendments
|
||||
|
||||
**Integration approach:**
|
||||
- REDCap API exports data to LabArchives entries
|
||||
- Automated data synchronization for longitudinal studies
|
||||
- HIPAA-compliant data handling
|
||||
|
||||
**Example workflow:**
|
||||
```python
|
||||
def sync_redcap_to_labarchives(redcap_api_token, client, uid, nbid):
|
||||
"""Sync REDCap data to LabArchives"""
|
||||
# Fetch REDCap data
|
||||
redcap_data = fetch_redcap_data(redcap_api_token)
|
||||
|
||||
# Create LabArchives entry
|
||||
entry_params = {
|
||||
'uid': uid,
|
||||
'nbid': nbid,
|
||||
'title': f"REDCap Data Export {datetime.now().strftime('%Y-%m-%d')}",
|
||||
'content': format_redcap_data_html(redcap_data)
|
||||
}
|
||||
response = client.make_call('entries', 'create_entry', params=entry_params)
|
||||
|
||||
return response
|
||||
```
|
||||
|
||||
**Compliance features:**
|
||||
- 21 CFR Part 11 compliance
|
||||
- Audit trail maintenance
|
||||
- Data integrity verification
|
||||
|
||||
### 6. Research Publishing
|
||||
|
||||
#### Qeios Integration
|
||||
|
||||
Research publishing platform integration for preprints and peer review.
|
||||
|
||||
**Use cases:**
|
||||
- Export research findings to preprint servers
|
||||
- Document publication workflows
|
||||
- Link published articles to lab notebooks
|
||||
|
||||
**Workflow:**
|
||||
- Export formatted entries from LabArchives
|
||||
- Submit to Qeios platform
|
||||
- Maintain bidirectional links between notebook and publication
|
||||
|
||||
#### SciSpace Integration
|
||||
|
||||
Literature management and citation integration.
|
||||
|
||||
**Use cases:**
|
||||
- Link references to experimental procedures
|
||||
- Maintain literature review in notebooks
|
||||
- Generate bibliographies for reports
|
||||
|
||||
**Features:**
|
||||
- Citation import from SciSpace to LabArchives
|
||||
- PDF annotation synchronization
|
||||
- Reference management
|
||||
|
||||
## OAuth Authentication for Integrations
|
||||
|
||||
LabArchives now uses OAuth 2.0 for new third-party integrations.
|
||||
|
||||
**OAuth flow for app developers:**
|
||||
|
||||
```python
|
||||
def labarchives_oauth_flow(client_id, client_secret, redirect_uri):
|
||||
"""Implement OAuth 2.0 flow for LabArchives integration"""
|
||||
import requests
|
||||
|
||||
# Step 1: Get authorization code
|
||||
auth_url = "https://mynotebook.labarchives.com/oauth/authorize"
|
||||
auth_params = {
|
||||
'client_id': client_id,
|
||||
'redirect_uri': redirect_uri,
|
||||
'response_type': 'code',
|
||||
'scope': 'read write'
|
||||
}
|
||||
# User visits auth_url and grants permission
|
||||
|
||||
# Step 2: Exchange code for access token
|
||||
token_url = "https://mynotebook.labarchives.com/oauth/token"
|
||||
token_params = {
|
||||
'client_id': client_id,
|
||||
'client_secret': client_secret,
|
||||
'redirect_uri': redirect_uri,
|
||||
'grant_type': 'authorization_code',
|
||||
'code': authorization_code # From redirect
|
||||
}
|
||||
|
||||
response = requests.post(token_url, data=token_params)
|
||||
tokens = response.json()
|
||||
|
||||
return tokens['access_token'], tokens['refresh_token']
|
||||
```
|
||||
|
||||
**OAuth advantages:**
|
||||
- More secure than API keys
|
||||
- Fine-grained permission control
|
||||
- Token refresh for long-running integrations
|
||||
- Revocable access
|
||||
|
||||
## Custom Integration Development
|
||||
|
||||
### General Workflow
|
||||
|
||||
For tools not officially supported, develop custom integrations:
|
||||
|
||||
1. **Export data** from source application (API or file export)
|
||||
2. **Transform format** to HTML or supported file type
|
||||
3. **Authenticate** with LabArchives API
|
||||
4. **Create entry** or upload attachment
|
||||
5. **Add metadata** via comments for traceability
|
||||
|
||||
### Example: Custom Integration Template
|
||||
|
||||
```python
|
||||
class LabArchivesIntegration:
|
||||
"""Template for custom LabArchives integrations"""
|
||||
|
||||
def __init__(self, config_path):
|
||||
self.client = self._init_client(config_path)
|
||||
self.uid = self._authenticate()
|
||||
|
||||
def _init_client(self, config_path):
|
||||
"""Initialize LabArchives client"""
|
||||
with open(config_path) as f:
|
||||
config = yaml.safe_load(f)
|
||||
return Client(config['api_url'],
|
||||
config['access_key_id'],
|
||||
config['access_password'])
|
||||
|
||||
def _authenticate(self):
|
||||
"""Get user ID"""
|
||||
# Implementation from authentication_guide.md
|
||||
pass
|
||||
|
||||
def export_data(self, source_data, nbid, title):
|
||||
"""Export data to LabArchives"""
|
||||
# Transform data to HTML
|
||||
html_content = self._transform_to_html(source_data)
|
||||
|
||||
# Create entry
|
||||
params = {
|
||||
'uid': self.uid,
|
||||
'nbid': nbid,
|
||||
'title': title,
|
||||
'content': html_content
|
||||
}
|
||||
response = self.client.make_call('entries', 'create_entry', params=params)
|
||||
|
||||
return extract_entry_id(response)
|
||||
|
||||
def _transform_to_html(self, data):
|
||||
"""Transform data to HTML format"""
|
||||
# Custom transformation logic
|
||||
pass
|
||||
```
|
||||
|
||||
## Integration Best Practices
|
||||
|
||||
1. **Version control:** Track which software version generated the data
|
||||
2. **Metadata preservation:** Include timestamps, user info, and processing parameters
|
||||
3. **File format standards:** Use open formats when possible (CSV, JSON, HTML)
|
||||
4. **Batch operations:** Implement rate limiting for bulk uploads
|
||||
5. **Error handling:** Implement retry logic with exponential backoff
|
||||
6. **Audit trails:** Log all API operations for compliance
|
||||
7. **Testing:** Validate integrations in test notebooks before production use
|
||||
|
||||
## Troubleshooting Integrations
|
||||
|
||||
### Common Issues
|
||||
|
||||
**Integration not appearing in LabArchives:**
|
||||
- Verify integration is enabled by administrator
|
||||
- Check OAuth permissions if using OAuth
|
||||
- Ensure compatible software version
|
||||
|
||||
**File upload failures:**
|
||||
- Verify file size limits (typically 2GB per file)
|
||||
- Check file format compatibility
|
||||
- Ensure sufficient storage quota
|
||||
|
||||
**Authentication errors:**
|
||||
- Verify API credentials are current
|
||||
- Check if integration-specific tokens have expired
|
||||
- Confirm user has necessary permissions
|
||||
|
||||
### Integration Support
|
||||
|
||||
For integration-specific issues:
|
||||
- Check software vendor documentation (e.g., GraphPad, Protocols.io)
|
||||
- Contact LabArchives support: support@labarchives.com
|
||||
- Review LabArchives knowledge base: help.labarchives.com
|
||||
|
||||
## Future Integration Opportunities
|
||||
|
||||
Potential integrations for custom development:
|
||||
- Electronic data capture (EDC) systems
|
||||
- Laboratory information management systems (LIMS)
|
||||
- Instrument data systems (chromatography, spectroscopy)
|
||||
- Cloud storage platforms (Box, Dropbox, Google Drive)
|
||||
- Project management tools (Asana, Monday.com)
|
||||
- Grant management systems
|
||||
|
||||
For custom integration development, contact LabArchives for API partnership opportunities.
|
||||
334
scientific-integrations/labarchive-integration/scripts/entry_operations.py
Executable file
334
scientific-integrations/labarchive-integration/scripts/entry_operations.py
Executable file
@@ -0,0 +1,334 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
LabArchives Entry Operations
|
||||
|
||||
Utilities for creating entries, uploading attachments, and managing notebook content.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import yaml
|
||||
import os
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
def load_config(config_path='config.yaml'):
|
||||
"""Load configuration from YAML file"""
|
||||
try:
|
||||
with open(config_path, 'r') as f:
|
||||
return yaml.safe_load(f)
|
||||
except FileNotFoundError:
|
||||
print(f"❌ Configuration file not found: {config_path}")
|
||||
print(" Run setup_config.py first to create configuration")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"❌ Error loading configuration: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def init_client(config):
|
||||
"""Initialize LabArchives API client"""
|
||||
try:
|
||||
from labarchivespy.client import Client
|
||||
return Client(
|
||||
config['api_url'],
|
||||
config['access_key_id'],
|
||||
config['access_password']
|
||||
)
|
||||
except ImportError:
|
||||
print("❌ labarchives-py package not installed")
|
||||
print(" Install with: pip install git+https://github.com/mcmero/labarchives-py")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def get_user_id(client, config):
|
||||
"""Get user ID via authentication"""
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
login_params = {
|
||||
'login_or_email': config['user_email'],
|
||||
'password': config['user_external_password']
|
||||
}
|
||||
|
||||
try:
|
||||
response = client.make_call('users', 'user_access_info', params=login_params)
|
||||
|
||||
if response.status_code == 200:
|
||||
uid = ET.fromstring(response.content)[0].text
|
||||
return uid
|
||||
else:
|
||||
print(f"❌ Authentication failed: HTTP {response.status_code}")
|
||||
print(f" Response: {response.content.decode('utf-8')[:200]}")
|
||||
sys.exit(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error during authentication: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def create_entry(client, uid, nbid, title, content=None, date=None):
|
||||
"""Create a new entry in a notebook"""
|
||||
print(f"\n📝 Creating entry: {title}")
|
||||
|
||||
# Prepare parameters
|
||||
params = {
|
||||
'uid': uid,
|
||||
'nbid': nbid,
|
||||
'title': title
|
||||
}
|
||||
|
||||
if content:
|
||||
# Ensure content is HTML formatted
|
||||
if not content.startswith('<'):
|
||||
content = f'<p>{content}</p>'
|
||||
params['content'] = content
|
||||
|
||||
if date:
|
||||
params['date'] = date
|
||||
|
||||
try:
|
||||
response = client.make_call('entries', 'create_entry', params=params)
|
||||
|
||||
if response.status_code == 200:
|
||||
print("✅ Entry created successfully")
|
||||
|
||||
# Try to extract entry ID from response
|
||||
try:
|
||||
import xml.etree.ElementTree as ET
|
||||
root = ET.fromstring(response.content)
|
||||
entry_id = root.find('.//entry_id')
|
||||
if entry_id is not None:
|
||||
print(f" Entry ID: {entry_id.text}")
|
||||
return entry_id.text
|
||||
except:
|
||||
pass
|
||||
|
||||
return True
|
||||
|
||||
else:
|
||||
print(f"❌ Entry creation failed: HTTP {response.status_code}")
|
||||
print(f" Response: {response.content.decode('utf-8')[:200]}")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error creating entry: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def create_comment(client, uid, nbid, entry_id, comment):
|
||||
"""Add a comment to an existing entry"""
|
||||
print(f"\n💬 Adding comment to entry {entry_id}")
|
||||
|
||||
params = {
|
||||
'uid': uid,
|
||||
'nbid': nbid,
|
||||
'entry_id': entry_id,
|
||||
'comment': comment
|
||||
}
|
||||
|
||||
try:
|
||||
response = client.make_call('entries', 'create_comment', params=params)
|
||||
|
||||
if response.status_code == 200:
|
||||
print("✅ Comment added successfully")
|
||||
return True
|
||||
else:
|
||||
print(f"❌ Comment creation failed: HTTP {response.status_code}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error creating comment: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def upload_attachment(client, config, uid, nbid, entry_id, file_path):
|
||||
"""Upload a file attachment to an entry"""
|
||||
import requests
|
||||
|
||||
file_path = Path(file_path)
|
||||
|
||||
if not file_path.exists():
|
||||
print(f"❌ File not found: {file_path}")
|
||||
return False
|
||||
|
||||
print(f"\n📎 Uploading attachment: {file_path.name}")
|
||||
print(f" Size: {file_path.stat().st_size / 1024:.2f} KB")
|
||||
|
||||
url = f"{config['api_url']}/entries/upload_attachment"
|
||||
|
||||
try:
|
||||
with open(file_path, 'rb') as f:
|
||||
files = {'file': f}
|
||||
data = {
|
||||
'uid': uid,
|
||||
'nbid': nbid,
|
||||
'entry_id': entry_id,
|
||||
'filename': file_path.name,
|
||||
'access_key_id': config['access_key_id'],
|
||||
'access_password': config['access_password']
|
||||
}
|
||||
|
||||
response = requests.post(url, files=files, data=data)
|
||||
|
||||
if response.status_code == 200:
|
||||
print("✅ Attachment uploaded successfully")
|
||||
return True
|
||||
else:
|
||||
print(f"❌ Upload failed: HTTP {response.status_code}")
|
||||
print(f" Response: {response.content.decode('utf-8')[:200]}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error uploading attachment: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def batch_upload(client, config, uid, nbid, entry_id, directory):
|
||||
"""Upload all files from a directory as attachments"""
|
||||
directory = Path(directory)
|
||||
|
||||
if not directory.is_dir():
|
||||
print(f"❌ Directory not found: {directory}")
|
||||
return
|
||||
|
||||
files = list(directory.glob('*'))
|
||||
files = [f for f in files if f.is_file()]
|
||||
|
||||
if not files:
|
||||
print(f"❌ No files found in {directory}")
|
||||
return
|
||||
|
||||
print(f"\n📦 Batch uploading {len(files)} files from {directory}")
|
||||
|
||||
successful = 0
|
||||
failed = 0
|
||||
|
||||
for file_path in files:
|
||||
if upload_attachment(client, config, uid, nbid, entry_id, file_path):
|
||||
successful += 1
|
||||
else:
|
||||
failed += 1
|
||||
|
||||
print("\n" + "="*60)
|
||||
print(f"Batch upload complete: {successful} successful, {failed} failed")
|
||||
print("="*60)
|
||||
|
||||
|
||||
def create_entry_with_attachments(client, config, uid, nbid, title, content,
|
||||
attachments):
|
||||
"""Create entry and upload multiple attachments"""
|
||||
# Create entry
|
||||
entry_id = create_entry(client, uid, nbid, title, content)
|
||||
|
||||
if not entry_id:
|
||||
print("❌ Cannot upload attachments without entry ID")
|
||||
return False
|
||||
|
||||
# Upload attachments
|
||||
for attachment_path in attachments:
|
||||
upload_attachment(client, config, uid, nbid, entry_id, attachment_path)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
"""Main command-line interface"""
|
||||
parser = argparse.ArgumentParser(
|
||||
description='LabArchives Entry Operations',
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Examples:
|
||||
# Create simple entry
|
||||
python3 entry_operations.py create --nbid 12345 --title "Experiment Results"
|
||||
|
||||
# Create entry with content
|
||||
python3 entry_operations.py create --nbid 12345 --title "Results" \\
|
||||
--content "PCR amplification successful"
|
||||
|
||||
# Create entry with HTML content
|
||||
python3 entry_operations.py create --nbid 12345 --title "Results" \\
|
||||
--content "<p>Results:</p><ul><li>Sample A: Positive</li></ul>"
|
||||
|
||||
# Upload attachment to existing entry
|
||||
python3 entry_operations.py upload --nbid 12345 --entry-id 67890 \\
|
||||
--file data.csv
|
||||
|
||||
# Batch upload multiple files
|
||||
python3 entry_operations.py batch-upload --nbid 12345 --entry-id 67890 \\
|
||||
--directory ./experiment_data/
|
||||
|
||||
# Add comment to entry
|
||||
python3 entry_operations.py comment --nbid 12345 --entry-id 67890 \\
|
||||
--text "Follow-up analysis needed"
|
||||
"""
|
||||
)
|
||||
|
||||
parser.add_argument('--config', default='config.yaml',
|
||||
help='Path to configuration file (default: config.yaml)')
|
||||
parser.add_argument('--nbid', required=True,
|
||||
help='Notebook ID')
|
||||
|
||||
subparsers = parser.add_subparsers(dest='command', help='Command to execute')
|
||||
|
||||
# Create entry command
|
||||
create_parser = subparsers.add_parser('create', help='Create new entry')
|
||||
create_parser.add_argument('--title', required=True, help='Entry title')
|
||||
create_parser.add_argument('--content', help='Entry content (HTML supported)')
|
||||
create_parser.add_argument('--date', help='Entry date (YYYY-MM-DD)')
|
||||
create_parser.add_argument('--attachments', nargs='+',
|
||||
help='Files to attach to the new entry')
|
||||
|
||||
# Upload attachment command
|
||||
upload_parser = subparsers.add_parser('upload', help='Upload attachment to entry')
|
||||
upload_parser.add_argument('--entry-id', required=True, help='Entry ID')
|
||||
upload_parser.add_argument('--file', required=True, help='File to upload')
|
||||
|
||||
# Batch upload command
|
||||
batch_parser = subparsers.add_parser('batch-upload',
|
||||
help='Upload all files from directory')
|
||||
batch_parser.add_argument('--entry-id', required=True, help='Entry ID')
|
||||
batch_parser.add_argument('--directory', required=True,
|
||||
help='Directory containing files to upload')
|
||||
|
||||
# Comment command
|
||||
comment_parser = subparsers.add_parser('comment', help='Add comment to entry')
|
||||
comment_parser.add_argument('--entry-id', required=True, help='Entry ID')
|
||||
comment_parser.add_argument('--text', required=True, help='Comment text')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.command:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
# Load configuration and initialize
|
||||
config = load_config(args.config)
|
||||
client = init_client(config)
|
||||
uid = get_user_id(client, config)
|
||||
|
||||
# Execute command
|
||||
if args.command == 'create':
|
||||
if args.attachments:
|
||||
create_entry_with_attachments(
|
||||
client, config, uid, args.nbid, args.title,
|
||||
args.content, args.attachments
|
||||
)
|
||||
else:
|
||||
create_entry(client, uid, args.nbid, args.title,
|
||||
args.content, args.date)
|
||||
|
||||
elif args.command == 'upload':
|
||||
upload_attachment(client, config, uid, args.nbid,
|
||||
args.entry_id, args.file)
|
||||
|
||||
elif args.command == 'batch-upload':
|
||||
batch_upload(client, config, uid, args.nbid,
|
||||
args.entry_id, args.directory)
|
||||
|
||||
elif args.command == 'comment':
|
||||
create_comment(client, uid, args.nbid, args.entry_id, args.text)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
269
scientific-integrations/labarchive-integration/scripts/notebook_operations.py
Executable file
269
scientific-integrations/labarchive-integration/scripts/notebook_operations.py
Executable file
@@ -0,0 +1,269 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
LabArchives Notebook Operations
|
||||
|
||||
Utilities for listing, backing up, and managing LabArchives notebooks.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import yaml
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def load_config(config_path='config.yaml'):
|
||||
"""Load configuration from YAML file"""
|
||||
try:
|
||||
with open(config_path, 'r') as f:
|
||||
return yaml.safe_load(f)
|
||||
except FileNotFoundError:
|
||||
print(f"❌ Configuration file not found: {config_path}")
|
||||
print(" Run setup_config.py first to create configuration")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"❌ Error loading configuration: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def init_client(config):
|
||||
"""Initialize LabArchives API client"""
|
||||
try:
|
||||
from labarchivespy.client import Client
|
||||
return Client(
|
||||
config['api_url'],
|
||||
config['access_key_id'],
|
||||
config['access_password']
|
||||
)
|
||||
except ImportError:
|
||||
print("❌ labarchives-py package not installed")
|
||||
print(" Install with: pip install git+https://github.com/mcmero/labarchives-py")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def get_user_id(client, config):
|
||||
"""Get user ID via authentication"""
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
login_params = {
|
||||
'login_or_email': config['user_email'],
|
||||
'password': config['user_external_password']
|
||||
}
|
||||
|
||||
try:
|
||||
response = client.make_call('users', 'user_access_info', params=login_params)
|
||||
|
||||
if response.status_code == 200:
|
||||
uid = ET.fromstring(response.content)[0].text
|
||||
return uid
|
||||
else:
|
||||
print(f"❌ Authentication failed: HTTP {response.status_code}")
|
||||
print(f" Response: {response.content.decode('utf-8')[:200]}")
|
||||
sys.exit(1)
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error during authentication: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def list_notebooks(client, uid):
|
||||
"""List all accessible notebooks for a user"""
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
print(f"\n📚 Listing notebooks for user ID: {uid}\n")
|
||||
|
||||
# Get user access info which includes notebook list
|
||||
login_params = {'uid': uid}
|
||||
|
||||
try:
|
||||
response = client.make_call('users', 'user_access_info', params=login_params)
|
||||
|
||||
if response.status_code == 200:
|
||||
root = ET.fromstring(response.content)
|
||||
notebooks = root.findall('.//notebook')
|
||||
|
||||
if not notebooks:
|
||||
print("No notebooks found")
|
||||
return []
|
||||
|
||||
notebook_list = []
|
||||
print(f"{'Notebook ID':<15} {'Name':<40} {'Role':<10}")
|
||||
print("-" * 70)
|
||||
|
||||
for nb in notebooks:
|
||||
nbid = nb.find('nbid').text if nb.find('nbid') is not None else 'N/A'
|
||||
name = nb.find('name').text if nb.find('name') is not None else 'Unnamed'
|
||||
role = nb.find('role').text if nb.find('role') is not None else 'N/A'
|
||||
|
||||
notebook_list.append({'nbid': nbid, 'name': name, 'role': role})
|
||||
print(f"{nbid:<15} {name:<40} {role:<10}")
|
||||
|
||||
print(f"\nTotal notebooks: {len(notebooks)}")
|
||||
return notebook_list
|
||||
|
||||
else:
|
||||
print(f"❌ Failed to list notebooks: HTTP {response.status_code}")
|
||||
return []
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error listing notebooks: {e}")
|
||||
return []
|
||||
|
||||
|
||||
def backup_notebook(client, uid, nbid, output_dir='backups', json_format=False,
|
||||
no_attachments=False):
|
||||
"""Backup a notebook"""
|
||||
print(f"\n💾 Backing up notebook {nbid}...")
|
||||
|
||||
# Create output directory
|
||||
output_path = Path(output_dir)
|
||||
output_path.mkdir(exist_ok=True)
|
||||
|
||||
# Prepare parameters
|
||||
params = {
|
||||
'uid': uid,
|
||||
'nbid': nbid,
|
||||
'json': 'true' if json_format else 'false',
|
||||
'no_attachments': 'true' if no_attachments else 'false'
|
||||
}
|
||||
|
||||
try:
|
||||
response = client.make_call('notebooks', 'notebook_backup', params=params)
|
||||
|
||||
if response.status_code == 200:
|
||||
# Determine file extension
|
||||
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||
|
||||
if no_attachments:
|
||||
ext = 'json' if json_format else 'xml'
|
||||
filename = f"notebook_{nbid}_{timestamp}.{ext}"
|
||||
else:
|
||||
filename = f"notebook_{nbid}_{timestamp}.7z"
|
||||
|
||||
output_file = output_path / filename
|
||||
|
||||
# Write to file
|
||||
with open(output_file, 'wb') as f:
|
||||
f.write(response.content)
|
||||
|
||||
file_size = output_file.stat().st_size / (1024 * 1024) # MB
|
||||
print(f"✅ Backup saved: {output_file}")
|
||||
print(f" File size: {file_size:.2f} MB")
|
||||
|
||||
return str(output_file)
|
||||
|
||||
else:
|
||||
print(f"❌ Backup failed: HTTP {response.status_code}")
|
||||
print(f" Response: {response.content.decode('utf-8')[:200]}")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error during backup: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def backup_all_notebooks(client, uid, output_dir='backups', json_format=False,
|
||||
no_attachments=False):
|
||||
"""Backup all accessible notebooks"""
|
||||
print("\n📦 Backing up all notebooks...\n")
|
||||
|
||||
notebooks = list_notebooks(client, uid)
|
||||
|
||||
if not notebooks:
|
||||
print("No notebooks to backup")
|
||||
return
|
||||
|
||||
successful = 0
|
||||
failed = 0
|
||||
|
||||
for nb in notebooks:
|
||||
nbid = nb['nbid']
|
||||
name = nb['name']
|
||||
|
||||
print(f"\n--- Backing up: {name} (ID: {nbid}) ---")
|
||||
|
||||
result = backup_notebook(client, uid, nbid, output_dir, json_format, no_attachments)
|
||||
|
||||
if result:
|
||||
successful += 1
|
||||
else:
|
||||
failed += 1
|
||||
|
||||
print("\n" + "="*60)
|
||||
print(f"Backup complete: {successful} successful, {failed} failed")
|
||||
print("="*60)
|
||||
|
||||
|
||||
def main():
|
||||
"""Main command-line interface"""
|
||||
parser = argparse.ArgumentParser(
|
||||
description='LabArchives Notebook Operations',
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Examples:
|
||||
# List all notebooks
|
||||
python3 notebook_operations.py list
|
||||
|
||||
# Backup specific notebook
|
||||
python3 notebook_operations.py backup --nbid 12345
|
||||
|
||||
# Backup all notebooks (JSON format, no attachments)
|
||||
python3 notebook_operations.py backup-all --json --no-attachments
|
||||
|
||||
# Backup to custom directory
|
||||
python3 notebook_operations.py backup --nbid 12345 --output my_backups/
|
||||
"""
|
||||
)
|
||||
|
||||
parser.add_argument('--config', default='config.yaml',
|
||||
help='Path to configuration file (default: config.yaml)')
|
||||
|
||||
subparsers = parser.add_subparsers(dest='command', help='Command to execute')
|
||||
|
||||
# List command
|
||||
subparsers.add_parser('list', help='List all accessible notebooks')
|
||||
|
||||
# Backup command
|
||||
backup_parser = subparsers.add_parser('backup', help='Backup a specific notebook')
|
||||
backup_parser.add_argument('--nbid', required=True, help='Notebook ID to backup')
|
||||
backup_parser.add_argument('--output', default='backups',
|
||||
help='Output directory (default: backups)')
|
||||
backup_parser.add_argument('--json', action='store_true',
|
||||
help='Return data in JSON format instead of XML')
|
||||
backup_parser.add_argument('--no-attachments', action='store_true',
|
||||
help='Exclude attachments from backup')
|
||||
|
||||
# Backup all command
|
||||
backup_all_parser = subparsers.add_parser('backup-all',
|
||||
help='Backup all accessible notebooks')
|
||||
backup_all_parser.add_argument('--output', default='backups',
|
||||
help='Output directory (default: backups)')
|
||||
backup_all_parser.add_argument('--json', action='store_true',
|
||||
help='Return data in JSON format instead of XML')
|
||||
backup_all_parser.add_argument('--no-attachments', action='store_true',
|
||||
help='Exclude attachments from backup')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.command:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
# Load configuration and initialize
|
||||
config = load_config(args.config)
|
||||
client = init_client(config)
|
||||
uid = get_user_id(client, config)
|
||||
|
||||
# Execute command
|
||||
if args.command == 'list':
|
||||
list_notebooks(client, uid)
|
||||
|
||||
elif args.command == 'backup':
|
||||
backup_notebook(client, uid, args.nbid, args.output, args.json, args.no_attachments)
|
||||
|
||||
elif args.command == 'backup-all':
|
||||
backup_all_notebooks(client, uid, args.output, args.json, args.no_attachments)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
205
scientific-integrations/labarchive-integration/scripts/setup_config.py
Executable file
205
scientific-integrations/labarchive-integration/scripts/setup_config.py
Executable file
@@ -0,0 +1,205 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
LabArchives Configuration Setup Script
|
||||
|
||||
This script helps create a config.yaml file with necessary credentials
|
||||
for LabArchives API access.
|
||||
"""
|
||||
|
||||
import yaml
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def get_regional_endpoint():
|
||||
"""Prompt user to select regional API endpoint"""
|
||||
print("\nSelect your regional API endpoint:")
|
||||
print("1. US/International (mynotebook.labarchives.com)")
|
||||
print("2. Australia (aunotebook.labarchives.com)")
|
||||
print("3. UK (uknotebook.labarchives.com)")
|
||||
print("4. Custom endpoint")
|
||||
|
||||
choice = input("\nEnter choice (1-4): ").strip()
|
||||
|
||||
endpoints = {
|
||||
'1': 'https://api.labarchives.com/api',
|
||||
'2': 'https://auapi.labarchives.com/api',
|
||||
'3': 'https://ukapi.labarchives.com/api'
|
||||
}
|
||||
|
||||
if choice in endpoints:
|
||||
return endpoints[choice]
|
||||
elif choice == '4':
|
||||
return input("Enter custom API endpoint URL: ").strip()
|
||||
else:
|
||||
print("Invalid choice, defaulting to US/International")
|
||||
return endpoints['1']
|
||||
|
||||
|
||||
def get_credentials():
|
||||
"""Prompt user for API credentials"""
|
||||
print("\n" + "="*60)
|
||||
print("LabArchives API Credentials")
|
||||
print("="*60)
|
||||
print("\nYou need two sets of credentials:")
|
||||
print("1. Institutional API credentials (from LabArchives administrator)")
|
||||
print("2. User authentication credentials (from your account settings)")
|
||||
print()
|
||||
|
||||
# Institutional credentials
|
||||
print("Institutional Credentials:")
|
||||
access_key_id = input(" Access Key ID: ").strip()
|
||||
access_password = input(" Access Password: ").strip()
|
||||
|
||||
# User credentials
|
||||
print("\nUser Credentials:")
|
||||
user_email = input(" Your LabArchives email: ").strip()
|
||||
|
||||
print("\nExternal Applications Password:")
|
||||
print("(Set this in your LabArchives Account Settings → Security & Privacy)")
|
||||
user_password = input(" External Applications Password: ").strip()
|
||||
|
||||
return {
|
||||
'access_key_id': access_key_id,
|
||||
'access_password': access_password,
|
||||
'user_email': user_email,
|
||||
'user_external_password': user_password
|
||||
}
|
||||
|
||||
|
||||
def create_config_file(config_data, output_path='config.yaml'):
|
||||
"""Create YAML configuration file"""
|
||||
with open(output_path, 'w') as f:
|
||||
yaml.dump(config_data, f, default_flow_style=False, sort_keys=False)
|
||||
|
||||
# Set file permissions to user read/write only for security
|
||||
os.chmod(output_path, 0o600)
|
||||
|
||||
print(f"\n✅ Configuration saved to: {os.path.abspath(output_path)}")
|
||||
print(" File permissions set to 600 (user read/write only)")
|
||||
|
||||
|
||||
def verify_config(config_path='config.yaml'):
|
||||
"""Verify configuration file can be loaded"""
|
||||
try:
|
||||
with open(config_path, 'r') as f:
|
||||
config = yaml.safe_load(f)
|
||||
|
||||
required_keys = ['api_url', 'access_key_id', 'access_password',
|
||||
'user_email', 'user_external_password']
|
||||
|
||||
missing = [key for key in required_keys if key not in config or not config[key]]
|
||||
|
||||
if missing:
|
||||
print(f"\n⚠️ Warning: Missing required fields: {', '.join(missing)}")
|
||||
return False
|
||||
|
||||
print("\n✅ Configuration file verified successfully")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n❌ Error verifying configuration: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def test_authentication(config_path='config.yaml'):
|
||||
"""Test authentication with LabArchives API"""
|
||||
print("\nWould you like to test the connection? (requires labarchives-py package)")
|
||||
test = input("Test connection? (y/n): ").strip().lower()
|
||||
|
||||
if test != 'y':
|
||||
return
|
||||
|
||||
try:
|
||||
# Try to import labarchives-py
|
||||
from labarchivespy.client import Client
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
# Load config
|
||||
with open(config_path, 'r') as f:
|
||||
config = yaml.safe_load(f)
|
||||
|
||||
# Initialize client
|
||||
print("\nInitializing client...")
|
||||
client = Client(
|
||||
config['api_url'],
|
||||
config['access_key_id'],
|
||||
config['access_password']
|
||||
)
|
||||
|
||||
# Test authentication
|
||||
print("Testing authentication...")
|
||||
login_params = {
|
||||
'login_or_email': config['user_email'],
|
||||
'password': config['user_external_password']
|
||||
}
|
||||
response = client.make_call('users', 'user_access_info', params=login_params)
|
||||
|
||||
if response.status_code == 200:
|
||||
# Extract UID
|
||||
uid = ET.fromstring(response.content)[0].text
|
||||
print(f"\n✅ Authentication successful!")
|
||||
print(f" User ID: {uid}")
|
||||
|
||||
# Get notebook count
|
||||
root = ET.fromstring(response.content)
|
||||
notebooks = root.findall('.//notebook')
|
||||
print(f" Accessible notebooks: {len(notebooks)}")
|
||||
|
||||
else:
|
||||
print(f"\n❌ Authentication failed: HTTP {response.status_code}")
|
||||
print(f" Response: {response.content.decode('utf-8')[:200]}")
|
||||
|
||||
except ImportError:
|
||||
print("\n⚠️ labarchives-py package not installed")
|
||||
print(" Install with: pip install git+https://github.com/mcmero/labarchives-py")
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n❌ Connection test failed: {e}")
|
||||
|
||||
|
||||
def main():
|
||||
"""Main setup workflow"""
|
||||
print("="*60)
|
||||
print("LabArchives API Configuration Setup")
|
||||
print("="*60)
|
||||
|
||||
# Check if config already exists
|
||||
if os.path.exists('config.yaml'):
|
||||
print("\n⚠️ config.yaml already exists")
|
||||
overwrite = input("Overwrite existing configuration? (y/n): ").strip().lower()
|
||||
if overwrite != 'y':
|
||||
print("Setup cancelled")
|
||||
return
|
||||
|
||||
# Get configuration
|
||||
api_url = get_regional_endpoint()
|
||||
credentials = get_credentials()
|
||||
|
||||
# Combine configuration
|
||||
config_data = {
|
||||
'api_url': api_url,
|
||||
**credentials
|
||||
}
|
||||
|
||||
# Create config file
|
||||
create_config_file(config_data)
|
||||
|
||||
# Verify
|
||||
verify_config()
|
||||
|
||||
# Test connection
|
||||
test_authentication()
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("Setup complete!")
|
||||
print("="*60)
|
||||
print("\nNext steps:")
|
||||
print("1. Add config.yaml to .gitignore if using version control")
|
||||
print("2. Use notebook_operations.py to list and backup notebooks")
|
||||
print("3. Use entry_operations.py to create entries and upload files")
|
||||
print("\nFor more information, see references/authentication_guide.md")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user