snotes updates, actions, attachments, easy user space

This commit is contained in:
2026-09-22 17:31:55 -07:00
parent ce30c6f4f7
commit abfbf3de1f
21 changed files with 669 additions and 53 deletions

View File

@@ -15,6 +15,7 @@ async def client(tmp_path, monkeypatch):
monkeypatch.setattr(settings, "data_dir", str(tmp_path / "notes"))
monkeypatch.setattr(settings, "database_path", str(tmp_path / "test.db"))
monkeypatch.setattr(settings, "actions_file", str(tmp_path / "actions.toml"))
monkeypatch.setattr(settings, "users", "schmeeve,ilya")
monkeypatch.setattr(settings, "remote_pass", "hunter2")
monkeypatch.setattr(settings, "secret_key", "test-secret")
@@ -37,6 +38,7 @@ async def remote_client(tmp_path, monkeypatch):
monkeypatch.setattr(settings, "data_dir", str(tmp_path / "notes"))
monkeypatch.setattr(settings, "database_path", str(tmp_path / "test.db"))
monkeypatch.setattr(settings, "actions_file", str(tmp_path / "actions.toml"))
monkeypatch.setattr(settings, "users", "schmeeve")
monkeypatch.setattr(settings, "remote_pass", "hunter2")
monkeypatch.setattr(settings, "secret_key", "test-secret")

89
tests/test_actions.py Normal file
View File

@@ -0,0 +1,89 @@
from __future__ import annotations
from backend import actions
def test_load_actions(tmp_path, monkeypatch):
f = tmp_path / "snotes.toml"
f.write_text(
'[[actions]]\nname = "task"\n'
'uri = "http://tasky.loc/new?title=#string1#"\n'
'link = "http://tasky.loc/?title=#string1#"\n'
'[[actions]]\nname = "other"\nuri = "http://x.loc/?q=#string1#"\n'
)
monkeypatch.setattr(actions.settings, "actions_file", str(f))
got = actions.load_actions(reload=True)
assert set(got) == {"task", "other"}
assert got["task"]["uri"] == "http://tasky.loc/new?title=#string1#"
assert got["task"]["link"] == "http://tasky.loc/?title=#string1#"
# "other" has no link -> link defaults to uri
assert got["other"]["link"] == "http://x.loc/?q=#string1#"
async def test_process_actions(monkeypatch):
monkeypatch.setattr(
actions,
"load_actions",
lambda: {
"task": {
"uri": "http://tasky.loc/new?title=#string1#",
"link": "http://tasky.loc/?title=#string1#",
}
},
)
called = []
async def fake_perform(uri):
called.append(uri)
return True
monkeypatch.setattr(actions, "_perform", fake_perform)
out = await actions.process_actions("before\n/task Go to the supermarket\nafter")
assert called == ["http://tasky.loc/new?title=Go%20to%20the%20supermarket"]
assert (
"[Go to the supermarket](http://tasky.loc/?title=Go%20to%20the%20supermarket)"
in out
)
async def test_process_actions_colon_separator(monkeypatch):
monkeypatch.setattr(
actions,
"load_actions",
lambda: {"task": {"uri": "http://x/?t=#string1#", "link": "http://x/?t=#string1#"}},
)
monkeypatch.setattr(actions, "_perform", lambda uri: _ok(uri))
out = await actions.process_actions("/task: shop milk")
assert "[shop milk](http://x/?t=shop%20milk)" in out
async def test_process_actions_failure_leaves_line(monkeypatch):
monkeypatch.setattr(
actions,
"load_actions",
lambda: {"task": {"uri": "http://x/?t=#string1#", "link": "http://x/?t=#string1#"}},
)
async def fail(uri):
return False
monkeypatch.setattr(actions, "_perform", fail)
out = await actions.process_actions("/task keep this line")
assert out == "/task keep this line"
async def test_process_actions_unknown_keyword(monkeypatch):
monkeypatch.setattr(
actions,
"load_actions",
lambda: {"task": {"uri": "http://x/?t=#string1#", "link": "http://x/?t=#string1#"}},
)
monkeypatch.setattr(actions, "_perform", lambda uri: _ok(uri))
out = await actions.process_actions("/nope do nothing")
assert out == "/nope do nothing"
async def _ok(uri):
return True

View File

@@ -34,6 +34,49 @@ async def test_users_seeded(client):
names = [u["name"] for u in r.json()]
assert "schmeeve" in names
assert "ilya" in names
assert "common" in names
async def test_create_note_in_common_space(client):
r = await client.post("/api/notes", json={"body": "shared note", "username": "common"})
assert r.status_code == 200
assert r.json()["username"] == "common"
async def test_move_note_between_spaces(client):
r = await client.post("/api/notes", json={"body": "start here"})
note_id = r.json()["id"]
assert r.json()["username"] == "schmeeve"
r2 = await client.put(f"/api/notes/{note_id}", json={"body": "moved", "username": "common"})
assert r2.status_code == 200
assert r2.json()["username"] == "common"
async def test_create_note_unknown_space(client):
r = await client.post("/api/notes", json={"body": "x", "username": "ghost"})
assert r.status_code == 404
async def test_upload_and_serve_attachment(client):
r = await client.post(
"/api/attachments",
files={"file": ("photo.png", b"fakeimage", "image/png")},
data={"username": "common"},
)
assert r.status_code == 200
data = r.json()
assert data["url"].startswith("/api/attachments/common/")
assert data["path"] == f"common/attachments/{data['url'].rsplit('/', 1)[-1]}"
r2 = await client.get(data["url"])
assert r2.status_code == 200
assert r2.content == b"fakeimage"
async def test_attachment_not_found(client):
r = await client.get("/api/attachments/common/does-not-exist.png")
assert r.status_code == 404
async def test_create_and_get_note(client):