feat(v1.4.0): Propriétés Avancées — collection_properties, 21 types, API CRUD
- Table collection_properties (21 types Notion: number, checkbox, url, email, phone, status, files, unique_id, ...)
- Auto-propriétés: created_time, created_by, last_edited_time, last_edited_by
- Service property_types.py: validation, formatage, auto-values
- API: GET /db/property-types/api, CRUD /db/{id}/properties/api, PUT/DELETE /db/properties/{id}/api
- 38/38 tests passent (+4 nouveaux tests v1.4)
- Version 1.3.0 → 1.4.0
- Docs: ROADMAP, CHANGELOG, WORKLOAD, README à jour
This commit is contained in:
+114
-3
@@ -34,7 +34,7 @@ def test_health(client):
|
||||
data = resp.json()
|
||||
assert "status" in data
|
||||
assert data["db"] is True
|
||||
assert data["version"] == "1.3.0"
|
||||
assert data["version"] == "1.4.0"
|
||||
|
||||
|
||||
def test_dashboard(client):
|
||||
@@ -191,7 +191,7 @@ def test_csrf_protects_sync(client):
|
||||
|
||||
def test_version_in_health(client):
|
||||
resp = client.get("/api/health")
|
||||
assert resp.json()["version"] == "1.3.0"
|
||||
assert resp.json()["version"] == "1.4.0"
|
||||
|
||||
|
||||
def test_db_tables_exist(client):
|
||||
@@ -204,7 +204,8 @@ def test_db_tables_exist(client):
|
||||
required = {"boards", "cards", "notes", "checklists", "checklist_items",
|
||||
"col_mapping", "users", "user_tokens",
|
||||
"project_properties", "property_values", "ai_keywords",
|
||||
"collections", "collection_pages", "collection_views"}
|
||||
"collections", "collection_pages", "collection_views",
|
||||
"collection_properties"}
|
||||
assert required <= names
|
||||
|
||||
|
||||
@@ -356,3 +357,113 @@ def test_boards_as_collections(client):
|
||||
data = resp.json()
|
||||
assert "boards" in data
|
||||
assert isinstance(data["boards"], list)
|
||||
|
||||
|
||||
# ── v1.4.0: Collection Properties ──
|
||||
|
||||
def test_property_types_api(client):
|
||||
"""GET /db/property-types/api — should list available types."""
|
||||
resp = client.get("/db/property-types/api")
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert "types" in data
|
||||
assert "text" in data["types"]
|
||||
assert "number" in data["types"]
|
||||
assert "checkbox" in data["types"]
|
||||
assert "status" in data["types"]
|
||||
|
||||
|
||||
def test_collection_properties_crud(client):
|
||||
"""Full CRUD on collection properties."""
|
||||
# Create collection
|
||||
resp = client.post("/db/api", json={"name": "Props Test DB"})
|
||||
coll_id = resp.json()["id"]
|
||||
|
||||
# List properties (empty)
|
||||
resp = client.get(f"/db/{coll_id}/properties/api")
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["properties"] == []
|
||||
|
||||
# Create a text property
|
||||
resp = client.post(f"/db/{coll_id}/properties/api", json={
|
||||
"name": "Description",
|
||||
"prop_type": "text",
|
||||
})
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["status"] == "created"
|
||||
prop_id = resp.json()["id"]
|
||||
|
||||
# Create a number property
|
||||
resp = client.post(f"/db/{coll_id}/properties/api", json={
|
||||
"name": "Estimation",
|
||||
"prop_type": "number",
|
||||
"number_format": "number",
|
||||
})
|
||||
assert resp.status_code == 200
|
||||
|
||||
# Create a status property with options
|
||||
resp = client.post(f"/db/{coll_id}/properties/api", json={
|
||||
"name": "State",
|
||||
"prop_type": "status",
|
||||
"options": [
|
||||
{"name": "Todo", "color": "gray"},
|
||||
{"name": "Done", "color": "green"},
|
||||
],
|
||||
})
|
||||
assert resp.status_code == 200
|
||||
|
||||
# Create a checkbox property
|
||||
resp = client.post(f"/db/{coll_id}/properties/api", json={
|
||||
"name": "Verified",
|
||||
"prop_type": "checkbox",
|
||||
})
|
||||
assert resp.status_code == 200
|
||||
|
||||
# List — should have 4
|
||||
resp = client.get(f"/db/{coll_id}/properties/api")
|
||||
assert len(resp.json()["properties"]) == 4
|
||||
|
||||
# Update a property
|
||||
resp = client.put(f"/db/properties/{prop_id}/api", json={
|
||||
"name": "Description Longue",
|
||||
})
|
||||
assert resp.status_code == 200
|
||||
|
||||
# Verify update
|
||||
resp = client.get(f"/db/{coll_id}/properties/api")
|
||||
names = [p["name"] for p in resp.json()["properties"]]
|
||||
assert "Description Longue" in names
|
||||
|
||||
# Delete a property
|
||||
resp = client.delete(f"/db/properties/{prop_id}/api")
|
||||
assert resp.status_code == 200
|
||||
|
||||
# Verify deletion
|
||||
resp = client.get(f"/db/{coll_id}/properties/api")
|
||||
assert len(resp.json()["properties"]) == 3
|
||||
|
||||
# Cleanup
|
||||
client.delete(f"/db/api/{coll_id}")
|
||||
|
||||
|
||||
def test_collection_properties_duplicate(client):
|
||||
"""Creating duplicate property name should return 409."""
|
||||
resp = client.post("/db/api", json={"name": "Dup Test"})
|
||||
coll_id = resp.json()["id"]
|
||||
|
||||
client.post(f"/db/{coll_id}/properties/api", json={"name": "Status", "prop_type": "select"})
|
||||
resp = client.post(f"/db/{coll_id}/properties/api", json={"name": "Status", "prop_type": "select"})
|
||||
assert resp.status_code == 409
|
||||
|
||||
client.delete(f"/db/api/{coll_id}")
|
||||
|
||||
|
||||
def test_collection_properties_validation(client):
|
||||
"""Validation: missing name should return 400."""
|
||||
resp = client.post("/db/api", json={"name": "Val Test"})
|
||||
coll_id = resp.json()["id"]
|
||||
|
||||
resp = client.post(f"/db/{coll_id}/properties/api", json={})
|
||||
assert resp.status_code == 400
|
||||
|
||||
client.delete(f"/db/api/{coll_id}")
|
||||
|
||||
Reference in New Issue
Block a user