atproto-calendar-import is a library and CLI tool for importing calendar events in python & rust

📅 atproto-calendar-import#

A Rust library and CLI tool for importing calendar events from external providers (Google Calendar, Microsoft Outlook) into the AT Protocol ecosystem. Built with atrium-rs for robust AT Protocol integration.

Rust License


🌟 Features#

  • Multi-Provider Support: Import from Google Calendar and Microsoft Outlook
  • OAuth2 Authentication: Secure authentication flows for external providers
  • AT Protocol Integration: Seamless publishing to AT Protocol repositories
  • Deduplication: Intelligent event deduplication to prevent duplicates
  • CLI Interface: Easy-to-use command-line interface
  • Configurable: Flexible configuration options
  • Error Handling: Comprehensive error handling with structured error codes

📦 Repository Structure#

atproto-calendar-import/RUST/
├── src/
│   ├── main.rs                # CLI binary entry point
│   ├── lib.rs                 # Core library exports
│   ├── auth.rs                # OAuth2 + AT Protocol authentication
│   ├── cli.rs                 # Command-line interface
│   ├── dedup.rs               # Event deduplication logic
│   ├── errors.rs              # Centralized error definitions
│   ├── pds.rs                 # AT Protocol PDS interactions
│   ├── import/                # External calendar provider integrations
│   │   ├── mod.rs             # Common import types and traits
│   │   ├── google.rs          # Google Calendar API integration
│   │   └── outlook.rs         # Microsoft Outlook/Graph API integration
│   └── transform/             # Event transformation and validation
│       ├── mod.rs             # Transform module exports
│       ├── validate.rs        # Event validation logic
│       └── convert.rs         # Provider-to-AT Protocol conversion
├── docs/                      # Additional documentation
├── import/                    # Legacy import scripts (deprecated)
├── transform/                 # Legacy transform scripts (deprecated)
├── target/                    # Rust build artifacts
├── Cargo.toml                 # Project metadata and dependencies
├── Cargo.lock                 # Dependency lock file
└── README.md                  # This file

🚀 Quick Start#

Prerequisites#

  • Rust ≥ 1.70
  • Cargo (included with Rust)
  • External calendar API credentials:
    • Google OAuth2 credentials for Google Calendar
    • Microsoft Graph API credentials for Outlook
  • AT Protocol account and PDS access

Installation#

  1. Clone the repository:
git clone <repository-url>
cd atproto-calendar-import/RUST
  1. Build the project:
cargo build --release
  1. Set up environment variables:
# Google Calendar (optional)
export GOOGLE_CLIENT_ID="your-google-client-id"
export GOOGLE_CLIENT_SECRET="your-google-client-secret"

# Microsoft Outlook (optional)
export OUTLOOK_CLIENT_ID="your-outlook-client-id"
export OUTLOOK_CLIENT_SECRET="your-outlook-client-secret"

# AT Protocol
export ATP_HANDLE="your-handle.bsky.social"
export ATP_PASSWORD="your-app-password"
export ATP_PDS_URL="https://bsky.social"  # or your PDS URL

Basic Usage#

Import from Google Calendar:

cargo run -- import-google --interactive

Import from Microsoft Outlook:

cargo run -- import-outlook --interactive

Test AT Protocol connection:

cargo run -- test-connection

Clear deduplication cache:

cargo run -- clear-cache

🛠️ Development#

Build Commands#

Task Command Description
Build (debug) cargo build Build in debug mode
Build (release) cargo build --release Build optimized release binary
Type Check cargo check Fast type checking without building
Format Code cargo fmt Format code using rustfmt
Lint Code cargo clippy Run Clippy linter
Run Tests cargo test Run all unit and integration tests
Run Specific Test cargo test <test_name> Run a specific test
Generate Documentation cargo doc --open Generate and open documentation

Testing#

# Run all tests
cargo test

# Run tests with output
cargo test -- --nocapture

# Run integration tests only
cargo test --test integration

# Run specific test
cargo test test_google_import

📋 CLI Commands#

Import Commands#

import-google#

Import events from Google Calendar.

cargo run -- import-google [OPTIONS]

Options:

  • -a, --access-token <TOKEN>: Use existing access token
  • --interactive: Start interactive OAuth2 flow
  • --skip-dedup: Skip deduplication check
  • --dry-run: Preview without publishing to AT Protocol

Examples:

# Interactive OAuth2 flow
cargo run -- import-google --interactive

# Use existing token
cargo run -- import-google --access-token "ya29.a0..."

# Dry run to preview events
cargo run -- import-google --interactive --dry-run

import-outlook#

Import events from Microsoft Outlook.

cargo run -- import-outlook [OPTIONS]

Options:

  • -a, --access-token <TOKEN>: Use existing access token
  • --interactive: Start interactive OAuth2 flow
  • --skip-dedup: Skip deduplication check
  • --dry-run: Preview without publishing to AT Protocol

Utility Commands#

test-connection#

Test connectivity to AT Protocol PDS.

cargo run -- test-connection

clear-cache#

Clear the deduplication cache for the current user.

cargo run -- clear-cache

⚙️ Configuration#

Environment Variables#

Required for AT Protocol#

  • ATP_HANDLE: Your AT Protocol handle (e.g., alice.bsky.social)
  • ATP_PASSWORD: Your AT Protocol app password
  • ATP_PDS_URL: PDS endpoint URL (default: https://bsky.social)

Optional for Google Calendar#

  • GOOGLE_CLIENT_ID: Google OAuth2 client ID
  • GOOGLE_CLIENT_SECRET: Google OAuth2 client secret

Optional for Microsoft Outlook#

  • OUTLOOK_CLIENT_ID: Microsoft Graph API client ID
  • OUTLOOK_CLIENT_SECRET: Microsoft Graph API client secret

Optional Configuration#

  • RUST_LOG: Log level (trace, debug, info, warn, error)
  • DATABASE_URL: PostgreSQL connection string (for persistent deduplication cache)

OAuth2 Setup#

Google Calendar API#

  1. Go to the Google Cloud Console
  2. Create a new project or select existing one
  3. Enable the Google Calendar API
  4. Create OAuth2 credentials
  5. Set redirect URI to http://localhost:8080/callback

Microsoft Graph API#

  1. Go to Azure Portal
  2. Navigate to Azure Active Directory > App registrations
  3. Create a new application registration
  4. Add Calendars.Read permission
  5. Set redirect URI to http://localhost:8080/callback

🔧 Architecture#

Core Components#

  • auth.rs: Handles OAuth2 flows for external providers and AT Protocol authentication
  • import/: Provider-specific importers (Google, Outlook) that fetch calendar events
  • transform/: Converts external event formats to AT Protocol lexicon format
  • dedup.rs: Prevents duplicate events using content hashing and metadata comparison
  • pds.rs: Publishes events to AT Protocol repositories via atrium-rs
  • cli.rs: Command-line interface and argument parsing

Data Flow#

  1. Authentication: OAuth2 flow with calendar provider + AT Protocol session
  2. Import: Fetch events from external calendar API
  3. Transform: Convert events to AT Protocol format
  4. Deduplicate: Check against existing events to prevent duplicates
  5. Publish: Create records in AT Protocol repository

Error Handling#

The project uses structured error codes for easy debugging:

  • 1xx: Authentication errors (OAuth2TokenFailed, InvalidAccessToken, etc.)
  • 2xx: Import errors (GoogleApiError, OutlookApiError, etc.)
  • 3xx: Transform errors (InvalidDateTimeFormat, MissingRequiredField, etc.)
  • 4xx: PDS errors (RecordCreationFailed, RepositoryNotFound, etc.)
  • 5xx: Internal errors (DeduplicationError, ConfigurationError, etc.)

🤝 Contributing#

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass: cargo test
  6. Format code: cargo fmt
  7. Run linter: cargo clippy
  8. Commit changes: git commit -m 'Add amazing feature'
  9. Push to branch: git push origin feature/amazing-feature
  10. Create a Pull Request

Code Style#

  • Follow Rust standard formatting (cargo fmt)
  • Add documentation for public APIs
  • Include unit tests for new functionality
  • Use structured error types from errors.rs
  • Add tracing instrumentation for important functions

📝 License#

This project is licensed under either of

at your option.



📞 Support#