Bug Description
When a user has an app installed and the app owner later makes it private, the app stays in the user's enabled list but cannot be uninstalled.
Root Cause
The disable endpoint (POST /v1/apps/disable) uses get_available_app_by_id() to look up the app before disabling it. This function filters out private apps not owned by the requesting user, returning None and causing a 404 — even though the user legitimately has the app installed.
backend/routers/apps.py:1698-1710:
@router.post('/v1/apps/disable')
def disable_app_endpoint(app_id: str, uid: str = Depends(auth.get_current_user_uid)):
app = get_available_app_by_id(app_id, uid) # returns None for private apps user doesn't own
...
backend/utils/apps.py:250-263 — get_available_app_by_id returns None for private apps where uid != app.uid.
Steps to Reproduce
- User A creates a public app
- User B installs the app
- User A makes the app private via
PATCH /v1/apps/{app_id}/change-visibility
- User B tries to disable/uninstall the app via
POST /v1/apps/disable?app_id=...
- Backend returns 404 — app is stuck in User B's enabled list with no way to remove it
Expected Behavior
Existing users should be grandfathered in — the app stays installed and visible to them, but they should always be able to uninstall it. Making an app private should only prevent new installs, not break existing ones.
Fix
In the disable endpoint, check if the user already has the app in their enabled list first. If so, let them disable it without going through get_available_app_by_id at all — no visibility check or DB lookup needed:
if app_id in get_enabled_apps(uid):
disable_app(uid, app_id)
return {'status': 'ok'}
A user should always be able to remove an app from their own enabled list.
Bug Description
When a user has an app installed and the app owner later makes it private, the app stays in the user's enabled list but cannot be uninstalled.
Root Cause
The disable endpoint (
POST /v1/apps/disable) usesget_available_app_by_id()to look up the app before disabling it. This function filters out private apps not owned by the requesting user, returningNoneand causing a 404 — even though the user legitimately has the app installed.backend/routers/apps.py:1698-1710:backend/utils/apps.py:250-263—get_available_app_by_idreturnsNonefor private apps whereuid != app.uid.Steps to Reproduce
PATCH /v1/apps/{app_id}/change-visibilityPOST /v1/apps/disable?app_id=...Expected Behavior
Existing users should be grandfathered in — the app stays installed and visible to them, but they should always be able to uninstall it. Making an app private should only prevent new installs, not break existing ones.
Fix
In the disable endpoint, check if the user already has the app in their enabled list first. If so, let them disable it without going through
get_available_app_by_idat all — no visibility check or DB lookup needed:A user should always be able to remove an app from their own enabled list.