Files
AdventureLog/backend/server/integrations/views/wanderer_view.py
Sean Morley ddcecd42df Enhance GitHub Actions workflows and improve error handling in backend services
- Added permissions for GitHub Actions workflows to manage contents, packages, and actions.
- Refactored SearchValidationError and IntegrationError classes to include custom messages and status codes.
- Improved logging in GlobalSearchView and WandererIntegrationViewSet to capture validation errors and exceptions more effectively.
- Updated error responses in billing views to provide user-friendly messages while logging detailed exceptions.
2026-06-27 13:02:04 -04:00

123 lines
4.5 KiB
Python

import logging
from rest_framework import viewsets, status
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.exceptions import ValidationError, NotFound
from integrations.models import WandererIntegration
from integrations.serializers import WandererIntegrationSerializer
from integrations.wanderer_services import (
IntegrationError,
TRAIL_EXPAND_AUTHOR,
TRAILS_LIST_PATHS,
make_wanderer_request,
validate_wanderer_connection,
)
logger = logging.getLogger(__name__)
class WandererIntegrationViewSet(viewsets.ViewSet):
permission_classes = [IsAuthenticated]
serializer_class = WandererIntegrationSerializer
def _get_obj(self):
return WandererIntegration.objects.filter(user=self.request.user).first()
def list(self, request):
inst = self._get_obj()
if not inst:
return Response(status=status.HTTP_404_NOT_FOUND)
serializer = self.serializer_class(inst)
return Response(serializer.data)
def create(self, request):
if WandererIntegration.objects.filter(user=request.user).exists():
raise ValidationError('Wanderer integration already exists. Use UPDATE instead.')
server_url = request.data.get('server_url')
api_key = request.data.get('api_key')
if not server_url or not api_key:
raise ValidationError('Must provide server_url and api_key in request data.')
try:
normalized_url = validate_wanderer_connection(server_url, api_key)
except IntegrationError as exc:
logger.warning('Wanderer connection validation failed during create: %s', exc.user_message)
raise ValidationError({'error': exc.user_message})
inst = WandererIntegration.objects.create(
user=request.user,
server_url=normalized_url,
api_key=api_key.strip(),
)
return Response(
self.serializer_class(inst).data,
status=status.HTTP_201_CREATED,
)
def update(self, request, pk=None):
inst = self._get_obj()
if not inst:
raise NotFound('Wanderer integration not found.')
if pk and str(inst.id) != str(pk):
raise NotFound('Wanderer integration not found.')
server_url = request.data.get('server_url', inst.server_url)
api_key = (request.data.get('api_key') or '').strip() or inst.api_key
if not server_url:
raise ValidationError('server_url is required.')
try:
normalized_url = validate_wanderer_connection(server_url, api_key)
except IntegrationError as exc:
logger.warning('Wanderer connection validation failed during update: %s', exc.user_message)
raise ValidationError({'error': exc.user_message})
inst.server_url = normalized_url
inst.api_key = api_key.strip()
inst.save(update_fields=['server_url', 'api_key'])
return Response(self.serializer_class(inst).data)
@action(detail=False, methods=['post'])
def disable(self, request):
inst = self._get_obj()
if not inst:
raise NotFound('Wanderer integration not found.')
inst.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
@action(detail=False, methods=['get'], url_path='trails')
def trails(self, request):
inst = self._get_obj()
if not inst:
raise NotFound('Wanderer integration not found.')
params = dict(request.query_params)
params.setdefault('expand', TRAIL_EXPAND_AUTHOR['expand'])
last_error = None
for path in TRAILS_LIST_PATHS:
try:
response = make_wanderer_request(
inst,
path,
params=params,
)
return Response(response.json())
except IntegrationError as exc:
last_error = exc
if exc.status_code == 404:
continue
logger.warning('Wanderer trails request failed: %s', exc.user_message)
raise ValidationError({'detail': 'Unable to fetch trails from Wanderer at this time.'})
logger.warning(
'Wanderer trails request failed for all known paths',
exc_info=last_error,
)
raise ValidationError({'detail': 'Unable to fetch trails from Wanderer at this time.'})