diff --git a/hermes/views.py b/hermes/views.py index 06289b8..04c85fe 100644 --- a/hermes/views.py +++ b/hermes/views.py @@ -634,7 +634,7 @@ def get(self, request): return Response(response) -class TopicApiView(RetrieveAPIView): +class TopicApiView(APIView): """ View to get list of available topics from SCiMMA Archive """ permission_classes = [] @@ -652,8 +652,11 @@ def get(self, request): topics = cache.get(f'user_{username}_{cred_name}_topics', None) if topics is None: archive_url = urljoin(settings.SCIMMA_ARCHIVE_BASE_URL, f'topics') - response = requests.get(archive_url, auth=scram_auth) - response.raise_for_status() + try: + response = requests.get(archive_url, auth=scram_auth) + response.raise_for_status() + except (requests.exceptions.HTTPError, requests.exceptions.ConnectionError) as e: + return Response({'error': str(e)}, status=e.response.status_code) topics = bson.loads(response.content) # Sort the topics to be in alphabetical ordering topics['topics'].sort() @@ -661,11 +664,12 @@ def get(self, request): return Response(topics, status=status.HTTP_200_OK) -class ProxyMessageDownloadView(RetrieveAPIView): +class ProxyMessageDownloadView(APIView): """ View to get a single file from the SCiMMA Archive given its uuid This is just a passthrough that injects the scram authentication into the request """ permission_classes = [] + def get(self, request, *args, **kwargs): uuid = self.kwargs['uuid'] content_type = request.GET.get('content_type', None) @@ -674,8 +678,11 @@ def get(self, request, *args, **kwargs): scram_auth = scram_auth_for_user(request.user) archive_url = urljoin(settings.SCIMMA_ARCHIVE_BASE_URL, f'msg/') archive_url += f'{uuid}/raw_file/{filename}' - response = requests.get(archive_url, auth=scram_auth, stream=True) - response.raise_for_status() + try: + response = requests.get(archive_url, auth=scram_auth, stream=True) + response.raise_for_status() + except (requests.exceptions.HTTPError, requests.exceptions.ConnectionError) as e: + return Response({'error': str(e)}, status=e.response.status_code) if not content_type: content_type = response.headers.get('content-type', 'application/octet-stream') if not filename: @@ -690,27 +697,55 @@ def get(self, request, *args, **kwargs): return proxy_response -class MessageApiView(RetrieveAPIView): +class MessageApiView(APIView): """ View to get a single message from the SCiMMA Archive given its uuid This is just a passthrough that injects the scram authentication into the request """ permission_classes = [] renderer_classes = [RemoveBytesRenderer] + def get_permissions(self): + if self.request.method == 'PATCH': + # Use a more restrictive permission for PATCH + return [IsAuthenticated()] + # Default permissions for GET, POST, DELETE, etc. + return [permission() for permission in self.permission_classes] + def get(self, request, *args, **kwargs): uuid = self.kwargs['uuid'] # Get the hop_auth for the user, or return an None scram_auth = scram_auth_for_user(request.user) archive_url = urljoin(settings.SCIMMA_ARCHIVE_BASE_URL, f'msg/') archive_url += uuid - response = requests.get(archive_url, auth=scram_auth) - response.raise_for_status() + try: + response = requests.get(archive_url, auth=scram_auth) + response.raise_for_status() + except (requests.exceptions.HTTPError, requests.exceptions.ConnectionError) as e: + return Response({'error': str(e)}, status=e.response.status_code) message = convert_message(bson.loads(response.content)) return Response(message, status=status.HTTP_200_OK) + def patch(self, request, *args, **kwargs): + uuid = self.kwargs['uuid'] + retracted = request.data.get('retracted') + if retracted is None or not isinstance(retracted, bool): + return Response({'error': "'retracted' must be provided as a boolean value."}, status=status.HTTP_400_BAD_REQUEST) + scram_auth = scram_auth_for_user(request.user) + archive_url = urljoin(settings.SCIMMA_ARCHIVE_BASE_URL, f'msg/') + archive_url += f'{uuid}/retraction?retracted={str(retracted).lower()}' + if scram_auth: + response = requests.put(archive_url, auth=scram_auth) + else: + return Response({'error': "User must be authenticated with a valid SCiMMA Auth credential to access this API"}, status=status.HTTP_401_UNAUTHORIZED) + try: + response.raise_for_status() + except requests.exceptions.HTTPError as e: + return Response({'error': str(e)}, status=e.response.status_code) + return Response({'success': 'true'}, status=status.HTTP_200_OK) + # TODO: Enhance this with other parameters when they are added to scimma archive -class QueryApiView(RetrieveAPIView): +class QueryApiView(APIView): """ View to query the SCiMMA Archive for messages """ permission_classes = [] @@ -735,13 +770,19 @@ def get(self, request): search_query = request.query_params.get('search_query', '') if search_query: query_params += f'&search_query={search_query}' + include_retracted = request.query_params.get('include_retracted', 'true') + if include_retracted.lower() in ['false', 'true']: + query_params += f"&include_retracted={include_retracted.lower()}" page = request.query_params.get('page', 0) if page: query_params += f'&page={page}' archive_url = urljoin(settings.SCIMMA_ARCHIVE_BASE_URL, f'messages') archive_url += query_params - response = requests.get(archive_url, auth=scram_auth) - response.raise_for_status() + try: + response = requests.get(archive_url, auth=scram_auth) + response.raise_for_status() + except (requests.exceptions.HTTPError, requests.exceptions.ConnectionError) as e: + return Response({'error': str(e)}, status=e.response.status_code) messages = convert_messages(bson.loads(response.content)) return Response(messages, status=status.HTTP_200_OK)