Skip to content

Commit 8409dc6

Browse files
author
Ilyas Gasanov
committed
[DOP-19793] Make queue name unique within a group
1 parent cd6386a commit 8409dc6

File tree

10 files changed

+33
-8
lines changed

10 files changed

+33
-8
lines changed

syncmaster/db/migrations/versions/2023-11-23_0003_create_queue_table.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@
2121
def upgrade():
2222
op.create_table(
2323
"queue",
24-
sa.Column("name", sa.String(length=128), nullable=False),
2524
sa.Column("id", sa.BigInteger(), nullable=False),
25+
sa.Column("name", sa.String(length=128), nullable=False),
26+
sa.Column("slug", sa.String(length=256), nullable=False),
2627
sa.Column("group_id", sa.BigInteger(), nullable=False),
2728
sa.Column("description", sa.String(length=512), nullable=False),
2829
sa.Column("created_at", sa.DateTime(), server_default=sa.text("now()"), nullable=False),
@@ -41,7 +42,7 @@ def upgrade():
4142
ondelete="CASCADE",
4243
),
4344
sa.PrimaryKeyConstraint("id", name=op.f("pk__queue")),
44-
sa.UniqueConstraint("name", name=op.f("uq__queue__name")),
45+
sa.UniqueConstraint("slug", name=op.f("uq__queue__slug")),
4546
)
4647
op.create_index(op.f("ix__queue__group_id"), "queue", ["group_id"], unique=False)
4748

syncmaster/db/models/queue.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717

1818

1919
class Queue(Base, ResourceMixin, TimestampMixin, DeletableMixin):
20-
name: Mapped[str] = mapped_column(String(128), nullable=False, unique=True)
20+
name: Mapped[str] = mapped_column(String(128), nullable=False)
21+
slug: Mapped[str] = mapped_column(String(256), nullable=False, unique=True)
2122

2223
transfers: Mapped[list[Transfer]] = relationship(back_populates="queue")
2324
group: Mapped[Group] = relationship(back_populates="queue")
@@ -31,4 +32,4 @@ class Queue(Base, ResourceMixin, TimestampMixin, DeletableMixin):
3132
)
3233

3334
def __repr__(self):
34-
return f"<Queue name={self.name} description={self.description}>"
35+
return f"<Queue name={self.name} slug={self.slug} description={self.description}>"

syncmaster/db/repositories/queue.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ async def get_resource_permission(self, user: User, resource_id: int) -> Permiss
197197
@staticmethod
198198
def _raise_error(err: DBAPIError) -> NoReturn:
199199
constraint = err.__cause__.__cause__.constraint_name
200-
if constraint == "uq__queue__name":
200+
if constraint == "uq__queue__slug":
201201
raise DuplicatedQueueNameError
202202

203203
raise SyncmasterError from err

syncmaster/schemas/v1/queue.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,29 @@
11
# SPDX-FileCopyrightText: 2023-2024 MTS PJSC
22
# SPDX-License-Identifier: Apache-2.0
3-
from pydantic import BaseModel, Field, constr
3+
from pydantic import BaseModel, Field, constr, model_validator
4+
from pydantic.json_schema import SkipJsonSchema
45

56
from syncmaster.schemas.v1.page import PageSchema
67

78

89
class CreateQueueSchema(BaseModel):
910
name: constr(max_length=128, pattern=r"^[-_a-zA-Z0-9]+$") = Field( # noqa: F722
1011
...,
11-
description="Queue name",
12+
description="Queue name that allows letters, numbers, dashes, and underscores",
1213
)
1314
group_id: int = Field(..., description="Queue owner group id")
1415
description: str = Field(default="", description="Additional description")
16+
slug: SkipJsonSchema[str] = Field(description="Generated slug for unique queue identification")
17+
18+
@model_validator(mode="before")
19+
def generate_slug(cls, values):
20+
values["slug"] = f"{values["group_id"]}-{values["name"]}"
21+
return values
1522

1623

1724
class ReadQueueSchema(BaseModel):
1825
name: str
26+
slug: str
1927
description: str | None = None
2028
group_id: int
2129
id: int

tests/test_unit/conftest.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import secrets
2+
from collections.abc import AsyncGenerator
23

34
import pytest_asyncio
45
from sqlalchemy.ext.asyncio import AsyncSession
@@ -289,7 +290,7 @@ async def group_queue(
289290
session: AsyncSession,
290291
settings: Settings,
291292
mock_group: MockGroup,
292-
) -> Queue:
293+
) -> AsyncGenerator[Queue, None]:
293294
queue = await create_queue(
294295
session=session,
295296
name=f"{secrets.token_hex(5)}_test_queue",

tests/test_unit/test_queue/test_create_queue.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ async def test_maintainer_plus_can_create_queue(
3535
"name": "New_queue",
3636
"description": "Some interesting description",
3737
"group_id": mock_group.group.id,
38+
"slug": f"{mock_group.group.id}-New_queue",
3839
}
3940
assert result.status_code == 200
4041
queue = (await session.scalars(select(Queue).filter_by(id=result.json()["id"]))).one()
@@ -43,6 +44,7 @@ async def test_maintainer_plus_can_create_queue(
4344
assert queue.group_id == mock_group.group.id
4445
assert queue.name == "New_queue"
4546
assert queue.description == "Some interesting description"
47+
assert queue.slug == f"{mock_group.group.id}-New_queue"
4648

4749
await session.delete(queue)
4850
await session.commit()
@@ -71,6 +73,7 @@ async def test_superuser_can_create_queue(
7173
"name": "New_queue",
7274
"description": "Some interesting description",
7375
"group_id": mock_group.group.id,
76+
"slug": f"{mock_group.group.id}-New_queue",
7477
}
7578
assert result.status_code == 200
7679
queue = (await session.scalars(select(Queue).filter_by(id=result.json()["id"]))).one()
@@ -79,6 +82,7 @@ async def test_superuser_can_create_queue(
7982
assert queue.group_id == mock_group.group.id
8083
assert queue.name == "New_queue"
8184
assert queue.description == "Some interesting description"
85+
assert queue.slug == f"{mock_group.group.id}-New_queue"
8286

8387
await session.delete(queue)
8488
await session.commit()

tests/test_unit/test_queue/test_read_queue.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ async def test_group_member_can_read_queue(
2828
"name": group_queue.name,
2929
"description": group_queue.description,
3030
"group_id": group_queue.group_id,
31+
"slug": f"{group_queue.group.id}-{group_queue.name}",
3132
}
3233
assert result.status_code == 200
3334

@@ -49,6 +50,7 @@ async def test_superuser_can_read_queue(
4950
"name": group_queue.name,
5051
"description": group_queue.description,
5152
"group_id": group_queue.group_id,
53+
"slug": f"{group_queue.group.id}-{group_queue.name}",
5254
}
5355
assert result.status_code == 200
5456

tests/test_unit/test_queue/test_read_queues.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ async def test_group_member_can_read_queues(
3535
"name": group_queue.name,
3636
"description": group_queue.description,
3737
"group_id": mock_group.id,
38+
"slug": f"{mock_group.id}-{group_queue.name}",
3839
},
3940
],
4041
"meta": {
@@ -73,6 +74,7 @@ async def test_superuser_can_read_queues(
7374
"name": group_queue.name,
7475
"description": group_queue.description,
7576
"group_id": mock_group.id,
77+
"slug": f"{mock_group.id}-{group_queue.name}",
7678
},
7779
],
7880
"meta": {
@@ -216,6 +218,7 @@ async def test_search_queues_with_query(
216218
"name": group_queue.name,
217219
"description": group_queue.description,
218220
"group_id": mock_group.id,
221+
"slug": f"{mock_group.id}-{group_queue.name}",
219222
},
220223
],
221224
}

tests/test_unit/test_queue/test_update_queue.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ async def test_maintainer_plus_can_update_queue(
3333
"name": group_queue.name,
3434
"description": "New description",
3535
"group_id": group_queue.group_id,
36+
"slug": f"{group_queue.group_id}-{group_queue.name}",
3637
}
3738
assert result.status_code == 200
3839

@@ -44,6 +45,7 @@ async def test_maintainer_plus_can_update_queue(
4445
"name": queue.name,
4546
"description": queue.description,
4647
"group_id": queue.group_id,
48+
"slug": f"{queue.group_id}-{queue.name}",
4749
}
4850

4951

@@ -70,6 +72,7 @@ async def test_superuser_can_update_queue(
7072
"name": group_queue.name,
7173
"description": "New description",
7274
"group_id": group_queue.group_id,
75+
"slug": f"{group_queue.group_id}-{group_queue.name}",
7376
}
7477

7578
queue = await session.get(Queue, group_queue.id)
@@ -80,6 +83,7 @@ async def test_superuser_can_update_queue(
8083
"name": queue.name,
8184
"description": queue.description,
8285
"group_id": queue.group_id,
86+
"slug": f"{queue.group_id}-{queue.name}",
8387
}
8488

8589

tests/test_unit/utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ async def create_queue(
7777
name=name,
7878
description=description,
7979
group_id=group_id,
80+
slug=f"{group_id}-{name}",
8081
)
8182
session.add(queue)
8283
await session.commit()

0 commit comments

Comments
 (0)