feat: step_integrations module with validate() + tier-filtered available list

This commit is contained in:
pyr0ball 2026-02-25 08:35:16 -08:00
parent eb0e7883b8
commit 6b093522bf
2 changed files with 68 additions and 0 deletions

View file

@ -0,0 +1,36 @@
"""Step 7 — Optional integrations (cloud storage, calendars, notifications).
This step is never mandatory validate() always returns [].
Helper functions support the wizard UI for tier-filtered integration cards.
"""
from __future__ import annotations
from pathlib import Path
def validate(data: dict) -> list[str]:
"""Integrations step is optional — never blocks Finish."""
return []
def get_available(tier: str) -> list[str]:
"""Return list of integration names available for the given tier.
An integration is available if the user's tier meets or exceeds the
integration's minimum required tier (as declared by cls.tier).
"""
from scripts.integrations import REGISTRY
from app.wizard.tiers import TIERS
available = []
for name, cls in REGISTRY.items():
try:
if TIERS.index(tier) >= TIERS.index(cls.tier):
available.append(name)
except ValueError:
pass # unknown tier string — skip
return available
def is_connected(name: str, config_dir: Path) -> bool:
"""Return True if a live config file exists for this integration."""
return (config_dir / "integrations" / f"{name}.yaml").exists()

View file

@ -110,3 +110,35 @@ def test_search_missing_both():
def test_search_none_values():
d = {"job_titles": None, "locations": None}
assert search_validate(d) != []
# ── Step Integrations ──────────────────────────────────────────────────────────
from app.wizard.step_integrations import validate as int_validate, get_available, is_connected
def test_integrations_always_passes():
assert int_validate({}) == []
assert int_validate({"connected": ["notion", "slack"]}) == []
def test_get_available_free_tier_includes_free():
available = get_available("free")
# Free integrations must always be available
for name in ["google_drive", "dropbox", "discord", "home_assistant"]:
assert name in available, f"{name} should be in free tier available list"
def test_get_available_free_tier_excludes_paid():
available = get_available("free")
# Paid integrations should NOT be available on free tier
for name in ["notion", "google_calendar", "slack"]:
assert name not in available, f"{name} should NOT be in free tier available list"
def test_get_available_paid_tier_includes_paid():
available = get_available("paid")
for name in ["notion", "google_sheets", "airtable", "slack", "google_calendar"]:
assert name in available, f"{name} should be in paid tier available list"
def test_is_connected_false_when_no_file(tmp_path):
assert is_connected("notion", tmp_path) is False
def test_is_connected_true_when_file_exists(tmp_path):
(tmp_path / "integrations").mkdir()
(tmp_path / "integrations" / "notion.yaml").write_text("token: x\n")
assert is_connected("notion", tmp_path) is True