2025-11-14 21:37:55 +01:00
2025-11-14 21:37:55 +01:00
2025-11-14 22:01:39 +01:00
2025-11-14 21:37:55 +01:00
2025-11-14 21:37:55 +01:00
2025-11-14 22:01:39 +01:00

studip-sync

studip-sync is a Rust CLI that performs a one-way sync of Stud.IP course materials (via the Uni Trier JSON:API) into a local directory tree. The tool persists config/state in TOML, talks to the API with HTTP Basic auth, and keeps the local filesystem organized as <download_root>/<semester>/<course>/<folder>/<files>.

Key Features

  • auth subcommand stores Base64-encoded credentials per profile (passwords are never logged).
  • list-courses fetches /users/me, paginates enrolled courses, infers semester keys, caches the metadata, and prints a concise table.
  • sync traverses every course folder/file tree, normalizes names, streams downloads to disk, tracks checksums/remote timestamps, and supports --dry-run plus --prune to delete orphaned files.
  • XDG-compliant config (~/.config/studip-sync/config.toml) and state (~/.local/share/studip-sync/state.toml) stores everything in TOML.
  • Extensive logging controls: --quiet, --verbose/-v, --debug, and --json.

Directory Layout & Data Files

  • Config lives under ${XDG_CONFIG_HOME:-~/.config}/studip-sync/config.toml. A default profile is created automatically and stores the basic_auth_b64, base URL, JSON:API path, download root, etc.
  • State is cached in ${XDG_DATA_HOME:-~/.local/share}/studip-sync/state.toml with per-profile sections for user/semester/course/file metadata.
  • Downloads default to ${XDG_DATA_HOME:-~/.local/share}/studip-sync/downloads, but you can override download_root in the config to point anywhere else. Each path segment is sanitized to keep names human-readable yet filesystem-safe.

Getting Started

  1. Prerequisites Install a recent Rust toolchain (Rust 1.75+ recommended) and ensure you can reach https://studip.uni-trier.de.
  2. Build & validate From the repo root run:
    cargo fmt --all -- --check
    cargo clippy --all-targets --all-features -- -D warnings
    cargo test
    
  3. First run:
    # Store credentials (prompts for username/password by default)
    cargo run -- auth
    
    # Inspect courses and cache semester data
    cargo run -- list-courses --refresh
    
    # Perform a dry-run sync to see planned actions
    cargo run -- sync --dry-run
    
    # Run the real sync (omit --dry-run); add --prune to delete stray files
    cargo run -- sync --prune
    
    Use --profile, --config-dir, or --data-dir when working with multiple identities or non-standard paths.

Configuration Reference

Example config.toml:

default_profile = "default"

[profiles.default]
base_url = "https://studip.uni-trier.de"
jsonapi_path = "/jsonapi.php/v1"
basic_auth_b64 = "base64(username:password)"
download_root = "/home/alex/StudIP"
max_concurrent_downloads = 3 # placeholder for future concurrency control
  • The file is written with 0600 permissions. Never commit credentials—auth manages them interactively or through --username/--password / STUDIP_SYNC_USERNAME|PASSWORD.
  • Multiple profiles can be added under [profiles.<name>]; pass --profile <name> when invoking the CLI to switch.

CLI Reference

Subcommand Description Helpful flags
auth Collect username/password, encode them, and save them to the active profile. --non-interactive, --username, --password
list-courses List cached or freshly fetched courses with semester keys and IDs. --refresh
sync Download files for every enrolled course into the local tree. --dry-run, --prune, --since (reserved for future API filters)

Global flags: --quiet, --debug, --json, -v/--verbose (stackable), --config-dir, --data-dir, --profile.

Sync Behavior

  1. Resolve user ID (cached in state.toml) and fetch current courses.
  2. Cache missing semesters via /semesters/{id} and infer keys like ws2425 / ss25.
  3. For each course:
    • Walk folders using the JSON:API pagination helpers; fetch nested folders via /folders/{id}/folders.
    • List file refs via /folders/{id}/file-refs, normalize filenames, and ensure unique siblings through a NameRegistry.
    • Skip downloads when the local file exists and matches the stored checksum / size / remote chdate.
    • Stream downloads to *.part, hash contents on the fly, then rename atomically to the final path.
  4. Maintain a set of remote files so --prune can remove local files that no longer exist remotely (and optionally delete now-empty directories).
  5. --dry-run prints planned work but never writes to disk.

Development Notes

  • The HTTP client limits itself to GETs with Basic auth; non-success responses are surfaced verbatim via anyhow.
  • All downloads currently run sequentially; ConfigProfile::max_concurrent_downloads is in place for a future bounded task executor.
  • Offline JSON:API documentation lives under docs/studip/ to keep this repo usable without network access.

Roadmap / Known Gaps

  1. Implement real concurrent downloads that honor max_concurrent_downloads.
  2. Wire --since into Stud.IP filters (if available) or local heuristics to reduce API load.
  3. Add unit/integration tests (semesters::infer_key, naming helpers, pruning) and consider fixtures for Stud.IP responses.
  4. Improve auth failure UX by detecting 401/403 and prompting the user to re-run studip-sync auth.
  5. Evaluate whether the crate should target Rust 2021 (per the original requirement) or explicitly document Rust 2024 as the minimum supported version.
Description
No description provided
Readme 546 KiB
Languages
Rust 100%