Compare commits

...

6 Commits

Author SHA1 Message Date
claude[bot]
2f64f1e412 fix(backend): handle slug collisions in store submission creation
Fixes UniqueViolationError when users try to create store submissions with duplicate slugs.

The issue was that create_store_submission() only checked for existing listings by agentGraphId,
but the database has a unique constraint on (owningUserId, slug). This caused failures when:
1. User creates agent A with slug "my-agent"
2. User creates agent B with same slug "my-agent"
3. Code didn't find duplicate (searched by agentGraphId only)
4. Database rejected due to unique constraint violation

Changes:
- Add slug uniqueness check before creating new store listing
- Generate unique slug with counter suffix when collision detected (e.g., "my-agent-1", "my-agent-2")
- Add safeguard to prevent infinite loop (max 100 attempts)
- Improve logging to track slug changes

Co-authored-by: Toran Bruce Richards <Torantulino@users.noreply.github.com>
2025-09-03 10:12:53 +00:00
claude[bot]
b2ae0d6b5e fix(backend): format code with ruff/black formatter
Co-authored-by: Toran Bruce Richards <Torantulino@users.noreply.github.com>
2025-09-02 16:51:11 +00:00
abhi1992002
98ef034108 fix(backend): update versioning logic in review store submission 2025-09-02 21:24:45 +05:30
Abhimanyu Yadav
ee9d34cdff Merge branch 'dev' into abhimanyuyadav/fix-review-store-submission 2025-09-02 21:24:29 +05:30
abhi1992002
9f9df5989a fix(backend): set imageUrls to an empty list in review store submission 2025-09-01 09:30:14 +05:30
abhi1992002
d601164a4b feat(backend): add imageUrls to review store submission 2025-08-30 19:08:14 +05:30

View File

@@ -608,13 +608,15 @@ async def create_store_submission(
)
# Check if listing already exists for this agent
existing_listing = await prisma.models.StoreListing.prisma().find_first(
where=prisma.types.StoreListingWhereInput(
agentGraphId=agent_id, owningUserId=user_id
existing_listing_by_agent = (
await prisma.models.StoreListing.prisma().find_first(
where=prisma.types.StoreListingWhereInput(
agentGraphId=agent_id, owningUserId=user_id
)
)
)
if existing_listing is not None:
if existing_listing_by_agent is not None:
logger.info(
f"Listing already exists for agent {agent_id}, creating new version instead"
)
@@ -624,7 +626,7 @@ async def create_store_submission(
user_id=user_id,
agent_id=agent_id,
agent_version=agent_version,
store_listing_id=existing_listing.id,
store_listing_id=existing_listing_by_agent.id,
name=name,
video_url=video_url,
image_urls=image_urls,
@@ -634,6 +636,38 @@ async def create_store_submission(
changes_summary=changes_summary,
)
# Check if slug already exists for this user and generate unique slug if needed
base_slug = slug
counter = 1
while True:
existing_listing_by_slug = (
await prisma.models.StoreListing.prisma().find_first(
where=prisma.types.StoreListingWhereInput(
owningUserId=user_id, slug=slug
)
)
)
if existing_listing_by_slug is None:
# Slug is available
break
# Generate a new slug with counter
slug = f"{base_slug}-{counter}"
counter += 1
# Prevent infinite loop - limit to 100 attempts
if counter > 100:
logger.error(
f"Unable to generate unique slug for user {user_id}, base slug {base_slug}"
)
raise backend.server.v2.store.exceptions.DatabaseError(
"Unable to generate unique slug for store submission"
)
if slug != base_slug:
logger.info(f"Slug collision detected, using {slug} instead of {base_slug}")
# If no existing listing, create a new one
data = prisma.types.StoreListingCreateInput(
slug=slug,
@@ -1273,20 +1307,35 @@ async def review_store_submission(
if is_approved and store_listing_version.AgentGraph:
heading = f"Sub-graph of {store_listing_version.name}v{store_listing_version.agentGraphVersion}"
# Temporary fix
latest_version = (
await prisma.models.StoreListingVersion.prisma().find_first(
where={"storeListingId": store_listing_version.StoreListing.id},
order={"version": "desc"},
)
)
next_version = (latest_version.version + 1) if latest_version else 1
sub_store_listing_versions = [
prisma.types.StoreListingVersionCreateWithoutRelationsInput(
agentGraphId=sub_graph.id,
agentGraphVersion=sub_graph.version,
name=sub_graph.name or heading,
version=next_version + i, # Unique version for each sub-graph
submissionStatus=prisma.enums.SubmissionStatus.APPROVED,
subHeading=heading,
imageUrls=store_listing_version.imageUrls or [],
categories=store_listing_version.categories or [],
description=f"{heading}: {sub_graph.description}",
changesSummary=f"This listing is added as a {heading} / #{store_listing_version.agentGraphId}.",
isAvailable=False, # Hide sub-graphs from the store by default.
submittedAt=datetime.now(tz=timezone.utc),
)
for sub_graph in await _get_missing_sub_store_listing(
store_listing_version.AgentGraph
for i, sub_graph in enumerate(
await _get_missing_sub_store_listing(
store_listing_version.AgentGraph
)
)
]