Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions server/mergin/sync/public_api_v2_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,6 @@ def create_project_version(id):
v_next_version = ProjectVersion.to_v_name(next_version)
version_dir = os.path.join(project.storage.project_dir, v_next_version)

pv = project.get_latest_version()
if pv and pv.name != version:
return ProjectVersionExists(version, pv.name).response(409)

try:
ChangesSchema().validate(changes)
upload_changes = ChangesSchema().dump(changes)
Expand Down Expand Up @@ -283,6 +279,10 @@ def create_project_version(id):
if requested_storage > project.workspace.storage:
return StorageLimitHit(current_usage, project.workspace.storage).response(422)

pv = project.get_latest_version()
if pv and pv.name != version:
return ProjectVersionExists(version, pv.name).response(409)

# we have done all checks but this request is just a dry-run
if request.json.get("check_only", False):
return NoContent, 204
Expand Down
35 changes: 35 additions & 0 deletions server/mergin/tests/test_public_api_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -1079,6 +1079,41 @@ def test_create_version_failures(client):
assert response.status_code == 409


def test_create_version_permanent_error_takes_priority(client):
"""Permanent errors (e.g. storage limit) must be reported before a
version conflict, otherwise clients would rebase/retry an upload that
is bound to fail anyway."""
project = Project.query.filter_by(
workspace_id=test_workspace_id, name=test_project
).first()

data = {
"version": "v0",
"changes": _get_changes_without_added(test_project_dir),
"check_only": True,
}
with patch.object(
Configuration,
"GLOBAL_STORAGE",
0,
):
response = client.post(f"v2/projects/{project.id}/versions", json=data)
assert response.status_code == 422
assert response.json["code"] == StorageLimitHit.code

# same must hold for the real (non check_only) upload
data["check_only"] = False
with patch.object(
Configuration,
"GLOBAL_STORAGE",
0,
):
response = client.post(f"v2/projects/{project.id}/versions", json=data)
assert response.status_code == 422
assert response.json["code"] == StorageLimitHit.code
assert project.latest_version == 1


def test_upload_chunk(client):
"""Test pushing a chunk to a project"""
project = Project.query.filter_by(
Expand Down
Loading