132 lines
4.8 KiB
Python
132 lines
4.8 KiB
Python
"""Références croisées des notes — Fusion #215 (ACC-1.3).
|
|
|
|
Parseur d'URL profondes (formes figées de dracodev-commons
|
|
``contrats/liens-profonds.md``), stockage JSON par utilisateur et
|
|
endpoints ``/api/refs`` (création par collage d'URL, liste, retrait).
|
|
"""
|
|
|
|
import pytest
|
|
|
|
from backend.external_refs import (
|
|
add_ref,
|
|
delete_ref,
|
|
get_ref,
|
|
list_refs,
|
|
parse_deep_link,
|
|
)
|
|
|
|
|
|
@pytest.fixture()
|
|
def refs_env(tmp_path, monkeypatch):
|
|
monkeypatch.setenv("OBSIGATE_EXTERNAL_REFS_DIR", str(tmp_path / "refs"))
|
|
return tmp_path
|
|
|
|
|
|
# ------------------------------------------------------------ parseur
|
|
|
|
@pytest.mark.parametrize("url,attendu", [
|
|
("https://tiktak.dracodev.net/?task=42",
|
|
("tiktak", "task", "42", "TikTak · tâche 42")),
|
|
("https://tiktak.dracodev.net/?list=7",
|
|
("tiktak", "list", "7", "TikTak · liste 7")),
|
|
("https://og.dracodev.net/#file=home-bruno:Projets%2FAlpha.md",
|
|
("obsigate", "note", "home-bruno:Projets/Alpha.md", "ObsiGate · Alpha.md")),
|
|
("https://flowdeck.dracodev.net/pages/15",
|
|
("flowdeck", "page", "15", "Flowdeck · page 15")),
|
|
("https://flowdeck.dracodev.net/collections/3",
|
|
("flowdeck", "project", "3", "Flowdeck · projet 3")),
|
|
("https://git.dracodev.net/Projets/fusion-trois-apps/issues/5",
|
|
("kanbante", "card", "Projets/fusion-trois-apps#5", "Kanbante · fusion-trois-apps #5")),
|
|
])
|
|
def test_parse_formes_reconnues(url, attendu):
|
|
assert parse_deep_link(url) == attendu
|
|
|
|
|
|
@pytest.mark.parametrize("url", [
|
|
"https://example.com/?task=1",
|
|
"https://og.dracodev.net/#file=sansdeuxpoints",
|
|
"https://og.dracodev.net/",
|
|
"https://flowdeck.dracodev.net/autre/12",
|
|
"https://git.dracodev.net/Projets/fusion-trois-apps",
|
|
"pas une url",
|
|
"",
|
|
])
|
|
def test_parse_formes_refusees(url):
|
|
assert parse_deep_link(url) is None
|
|
|
|
|
|
# ------------------------------------------------------------ stockage
|
|
|
|
def test_stockage_cycle(refs_env):
|
|
ref = add_ref("alice", "TestVault", "Note A.md", "tiktak", "task", "42",
|
|
"https://tiktak.dracodev.net/?task=42", "TikTak · tâche 42")
|
|
assert ref["owner_type"] == "obsigate.note"
|
|
assert ref["owner_id"] == "TestVault:Note A.md"
|
|
assert get_ref("alice", ref["id"])["target_id"] == "42"
|
|
|
|
assert [r["id"] for r in list_refs("alice", "TestVault", "Note A.md")] == [ref["id"]]
|
|
assert list_refs("alice", "TestVault", "Autre.md") == []
|
|
assert list_refs("bob", "TestVault", "Note A.md") == [] # par utilisateur
|
|
|
|
removed = delete_ref("alice", ref["id"])
|
|
assert removed["id"] == ref["id"]
|
|
assert delete_ref("alice", ref["id"]) is None
|
|
assert list_refs("alice", "TestVault", "Note A.md") == []
|
|
|
|
|
|
# ------------------------------------------------------------ API
|
|
|
|
def test_api_cycle_complet(client, refs_env):
|
|
r = client.post("/api/refs", json={
|
|
"vault": "TestVault", "path": "Note A.md",
|
|
"url": "https://flowdeck.dracodev.net/collections/3",
|
|
})
|
|
assert r.status_code == 201, r.text
|
|
ref = r.json()
|
|
assert ref["target_app"] == "flowdeck"
|
|
assert ref["target_type"] == "project"
|
|
assert ref["label"] == "Flowdeck · projet 3"
|
|
|
|
r = client.post("/api/refs", json={
|
|
"vault": "TestVault", "path": "Note A.md",
|
|
"url": "https://tiktak.dracodev.net/?task=9", "label": "Ma tâche",
|
|
})
|
|
assert r.status_code == 201, r.text
|
|
assert r.json()["label"] == "Ma tâche"
|
|
|
|
r = client.get("/api/refs", params={"vault": "TestVault", "path": "Note A.md"})
|
|
assert r.status_code == 200
|
|
assert [x["target_app"] for x in r.json()["refs"]] == ["flowdeck", "tiktak"]
|
|
|
|
r = client.delete(f"/api/refs/{ref['id']}")
|
|
assert r.status_code == 200
|
|
r = client.get("/api/refs", params={"vault": "TestVault", "path": "Note A.md"})
|
|
assert [x["target_app"] for x in r.json()["refs"]] == ["tiktak"]
|
|
|
|
|
|
def test_api_url_inconnue_422(client, refs_env):
|
|
r = client.post("/api/refs", json={
|
|
"vault": "TestVault", "path": "Note A.md",
|
|
"url": "https://example.com/whatever",
|
|
})
|
|
assert r.status_code == 422
|
|
|
|
|
|
def test_api_delete_introuvable_404(client, refs_env):
|
|
r = client.delete("/api/refs/inexistant")
|
|
assert r.status_code == 404
|
|
|
|
|
|
def test_api_vault_sans_acces_403(admin_client, refs_env):
|
|
"""Auth activée : un utilisateur limité à TestVault reçoit 403 ailleurs."""
|
|
r = admin_client.post("/api/auth/login",
|
|
json={"username": "normaluser", "password": "normal123"})
|
|
assert r.status_code == 200, r.text
|
|
headers = {"Authorization": f"Bearer {r.json()['access_token']}"}
|
|
r = admin_client.get("/api/refs", headers=headers,
|
|
params={"vault": "VaultFantome", "path": "x.md"})
|
|
assert r.status_code == 403
|
|
r = admin_client.get("/api/refs", headers=headers,
|
|
params={"vault": "TestVault", "path": "x.md"})
|
|
assert r.status_code == 200
|