feat: add webhook management UI and BeforeNodeDeletedEvent support
Added comprehensive webhook management capabilities including: Webhook Client & API: - Added WebhooksClient for Nextcloud webhooks API integration - Create, list, update, and delete webhooks programmatically - Support for event filters in webhook registration Webhook Presets: - Added preset system for common webhook configurations - notes_sync: BeforeNodeDeletedEvent for Notes file operations - calendar_sync: Calendar events (create, update, delete) - deck_sync: Deck card operations - files_sync: File system changes - forms_sync: Form submissions (conditional) - Filter presets by installed apps Admin UI: - Added multi-pane app view with tabs (User Info, Vector Sync, Webhooks) - Webhooks tab for admin users only - Enable/disable preset webhooks via UI - View currently registered webhooks - Uses htmx for dynamic loading and Alpine.js for tab state - Admin permission checking via OCS API CLI Improvements: - Refactored CLI to separate module (cli.py) - Updated entry point in pyproject.toml BeforeNodeDeletedEvent Fix: - Updated ADR-010 to document NodeDeletedEvent issue - BeforeNodeDeletedEvent includes node.id before deletion - NodeDeletedEvent lacks node.id (file already deleted) - Implemented per Nextcloud maintainer recommendation Testing: - Added comprehensive webhook client tests - Added webhook preset filtering tests - Added admin permission tests Configuration: - Updated docker-compose.yml Qdrant settings 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
"""Permission checking utilities for Nextcloud admin operations."""
|
||||
|
||||
import logging
|
||||
|
||||
from httpx import AsyncClient
|
||||
from starlette.requests import Request
|
||||
|
||||
from nextcloud_mcp_server.client.users import UsersClient
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def is_nextcloud_admin(request: Request, http_client: AsyncClient) -> bool:
|
||||
"""Check if the authenticated user is a Nextcloud administrator.
|
||||
|
||||
This function extracts the username from the session/request context
|
||||
and checks if the user is a member of the "admin" group in Nextcloud.
|
||||
|
||||
Args:
|
||||
request: Starlette request object with authenticated user
|
||||
http_client: Authenticated HTTP client for Nextcloud API calls
|
||||
|
||||
Returns:
|
||||
True if user is admin, False otherwise
|
||||
|
||||
Example:
|
||||
```python
|
||||
if await is_nextcloud_admin(request, http_client):
|
||||
# Show admin-only features
|
||||
pass
|
||||
```
|
||||
"""
|
||||
try:
|
||||
# Extract username from authenticated session
|
||||
username = request.user.display_name
|
||||
if not username:
|
||||
logger.warning("No username found in authenticated session")
|
||||
return False
|
||||
|
||||
# Query Nextcloud for user's group memberships
|
||||
users_client = UsersClient(http_client, username)
|
||||
user_groups = await users_client.get_user_groups(username)
|
||||
|
||||
# Check if user is in the admin group
|
||||
is_admin = "admin" in user_groups
|
||||
logger.debug(
|
||||
f"Admin check for user '{username}': {is_admin} (groups: {user_groups})"
|
||||
)
|
||||
|
||||
return is_admin
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error checking admin permissions: {e}", exc_info=True)
|
||||
return False
|
||||
Reference in New Issue
Block a user