mirror of
https://github.com/mealie-recipes/mealie.git
synced 2026-05-17 23:37:35 -04:00
fix: return HTTP 400 for duplicate tag and label creation (#7638)
Co-authored-by: voidborne-d <voidborne-d@users.noreply.github.com>
This commit is contained in:
@@ -54,7 +54,11 @@ class MultiPurposeLabelsController(BaseCrudController):
|
|||||||
|
|
||||||
@router.post("", response_model=MultiPurposeLabelOut)
|
@router.post("", response_model=MultiPurposeLabelOut)
|
||||||
def create_one(self, data: MultiPurposeLabelCreate):
|
def create_one(self, data: MultiPurposeLabelCreate):
|
||||||
new_label = self.service.create_one(data)
|
try:
|
||||||
|
new_label = self.service.create_one(data)
|
||||||
|
except Exception as ex:
|
||||||
|
self.mixins.handle_exception(ex)
|
||||||
|
raise # handle_exception always raises; this satisfies static analysis
|
||||||
self.publish_event(
|
self.publish_event(
|
||||||
event_type=EventTypes.label_created,
|
event_type=EventTypes.label_created,
|
||||||
document_data=EventLabelData(operation=EventOperation.create, label_id=new_label.id),
|
document_data=EventLabelData(operation=EventOperation.create, label_id=new_label.id),
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class TagController(BaseCrudController):
|
|||||||
def create_one(self, tag: TagIn):
|
def create_one(self, tag: TagIn):
|
||||||
"""Creates a Tag in the database"""
|
"""Creates a Tag in the database"""
|
||||||
save_data = mapper.cast(tag, TagSave, group_id=self.group_id)
|
save_data = mapper.cast(tag, TagSave, group_id=self.group_id)
|
||||||
new_tag = self.repo.create(save_data)
|
new_tag = self.mixins.create_one(save_data)
|
||||||
|
|
||||||
if new_tag:
|
if new_tag:
|
||||||
self.publish_event(
|
self.publish_event(
|
||||||
|
|||||||
@@ -191,6 +191,24 @@ def test_organizer_association(
|
|||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("route", organizer_routes, ids=test_ids)
|
||||||
|
def test_organizer_create_duplicate_name_returns_400(
|
||||||
|
api_client: TestClient,
|
||||||
|
unique_user: TestUser,
|
||||||
|
route: RoutesBase,
|
||||||
|
):
|
||||||
|
# Regression test for #7582: POSTing a duplicate name to organizer endpoints
|
||||||
|
# leaked the sqlalchemy IntegrityError as an HTTP 500. The expected behavior,
|
||||||
|
# matching other organizer endpoints (foods, units, tools), is HTTP 400.
|
||||||
|
data = {"name": random_string(10)}
|
||||||
|
|
||||||
|
response = api_client.post(route.base, json=data, headers=unique_user.token)
|
||||||
|
assert response.status_code == 201
|
||||||
|
|
||||||
|
response = api_client.post(route.base, json=data, headers=unique_user.token)
|
||||||
|
assert response.status_code == 400
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("route, recipe_key", association_data, ids=test_ids)
|
@pytest.mark.parametrize("route, recipe_key", association_data, ids=test_ids)
|
||||||
def test_organizer_get_by_slug(
|
def test_organizer_get_by_slug(
|
||||||
api_client: TestClient,
|
api_client: TestClient,
|
||||||
|
|||||||
@@ -20,6 +20,21 @@ def create_labels(api_client: TestClient, unique_user: TestUser, count: int = 10
|
|||||||
return labels
|
return labels
|
||||||
|
|
||||||
|
|
||||||
|
def test_label_create_duplicate_name_returns_400(api_client: TestClient, unique_user_fn_scoped: TestUser):
|
||||||
|
# Regression test for #7582: POSTing a duplicate label name leaked the
|
||||||
|
# sqlalchemy IntegrityError as an HTTP 500. The expected behavior, matching
|
||||||
|
# the other organizer endpoints (foods, units, tools, tags, categories),
|
||||||
|
# is HTTP 400. The function-scoped fixture avoids leaking the created label
|
||||||
|
# into the module-scoped `unique_user` group state used by sibling tests.
|
||||||
|
payload = {"name": random_string(), "color": "#ff0000"}
|
||||||
|
|
||||||
|
response = api_client.post(api_routes.groups_labels, json=payload, headers=unique_user_fn_scoped.token)
|
||||||
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
response = api_client.post(api_routes.groups_labels, json=payload, headers=unique_user_fn_scoped.token)
|
||||||
|
assert response.status_code == 400
|
||||||
|
|
||||||
|
|
||||||
def test_new_list_creates_list_labels(api_client: TestClient, unique_user: TestUser):
|
def test_new_list_creates_list_labels(api_client: TestClient, unique_user: TestUser):
|
||||||
labels = create_labels(api_client, unique_user)
|
labels = create_labels(api_client, unique_user)
|
||||||
response = api_client.post(
|
response = api_client.post(
|
||||||
|
|||||||
Reference in New Issue
Block a user