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
23 changes: 23 additions & 0 deletions backend/src/syfthub/api/endpoints/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,29 @@ async def update_endpoint(
return endpoint_service.update_endpoint(endpoint_id, endpoint_data, current_user)


@router.get("/{endpoint_slug}/exists", response_model=bool)
async def endpoint_exists_for_user(
endpoint_slug: str,
current_user: Annotated[User, Depends(get_current_active_user)],
endpoint_service: Annotated[EndpointService, Depends(get_endpoint_service)],
) -> bool:
"""Check if endpoint exists for user."""
return endpoint_service.endpoint_exists_for_user(endpoint_slug, current_user)


@router.patch("/{endpoint_slug}", response_model=EndpointResponse)
async def update_endpoint_by_slug(
endpoint_slug: str,
endpoint_data: EndpointUpdate,
current_user: Annotated[User, Depends(get_current_active_user)],
endpoint_service: Annotated[EndpointService, Depends(get_endpoint_service)],
) -> EndpointResponse:
"""Update a endpoint by slug."""
return endpoint_service.update_endpoint_by_slug(
endpoint_slug, endpoint_data, current_user
)


@router.delete("/{endpoint_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_endpoint(
endpoint_id: int,
Expand Down
48 changes: 48 additions & 0 deletions backend/src/syfthub/services/endpoint_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,11 @@ def get_endpoint_by_user_and_slug(
"""Get endpoint by user and slug."""
return self.endpoint_repository.get_by_user_and_slug(user_id, slug)

def endpoint_exists_for_user(self, slug: str, current_user: User) -> bool:
"""Check if endpoint exists for user."""
endpoint = self.endpoint_repository.get_by_user_and_slug(current_user.id, slug)
return endpoint is not None

def get_endpoint_by_org_and_slug(
self, org_id: int, slug: str
) -> Optional[Endpoint]:
Expand Down Expand Up @@ -331,6 +336,49 @@ def update_endpoint(

return self._to_response_with_urls(updated_endpoint)

def update_endpoint_by_slug(
self, endpoint_slug: str, endpoint_data: EndpointUpdate, current_user: User
) -> EndpointResponse:
"""Update endpoint by slug."""
endpoint = self.endpoint_repository.get_by_user_and_slug(
current_user.id, endpoint_slug
)
if not endpoint:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Endpoint not found",
)

if not self._can_modify_endpoint(endpoint, current_user):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Permission denied: insufficient permissions",
)

# Validate contributors if they are being updated
if endpoint_data.contributors is not None:
valid_contributors = self._validate_contributors(endpoint_data.contributors)
# Ensure at least one contributor exists (the user performing the update)
# For user-owned endpoints, the owner should always be included
# For org-owned endpoints, ensure the updating user is included if list would be empty
if endpoint.user_id and endpoint.user_id not in valid_contributors:
valid_contributors.append(endpoint.user_id)
elif not endpoint.user_id and current_user.id not in valid_contributors:
# Org-owned endpoint: ensure at least the updating user is a contributor
valid_contributors.append(current_user.id)
endpoint_data.contributors = valid_contributors

updated_endpoint = self.endpoint_repository.update_endpoint(
endpoint.id, endpoint_data
)
if not updated_endpoint:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to update endpoint",
)

return self._to_response_with_urls(updated_endpoint)

def admin_update_endpoint(
self, endpoint_id: int, admin_data: EndpointAdminUpdate, current_user: User
) -> EndpointResponse:
Expand Down
Loading