diff --git a/rdmo/projects/viewsets.py b/rdmo/projects/viewsets.py index 3ca669e76..4db668db7 100644 --- a/rdmo/projects/viewsets.py +++ b/rdmo/projects/viewsets.py @@ -522,27 +522,51 @@ def dispatch(self, *args, **kwargs): def retrieve(self, request, *args, **kwargs): page = self.get_object() conditions = page.conditions.select_related('source', 'target_option') - values = self.project.values.filter(snapshot=None).select_related('attribute', 'option') + # Check if the current page meets conditions if check_conditions(conditions, values): serializer = self.get_serializer(page) return Response(serializer.data) else: - if request.GET.get('back') == 'true': - prev_page = self.project.catalog.get_prev_page(page) - if prev_page is not None: - url = reverse('v1-projects:project-page-detail', - args=[self.project.id, prev_page.id]) + '?back=true' - return HttpResponseRedirect(url, status=303) + # Determine the direction of navigation (back or forward) + direction = 'prev' if request.GET.get('back') == 'true' else 'next' + next_page = self._find_next_relevant_page(page, direction) + + if next_page: + url = reverse('v1-projects:project-page-detail', args=[self.project.id, next_page.id]) + if direction == 'prev': + url += '?back=true' + return HttpResponseRedirect(url, status=303) + + # If no next relevant page is found, end of catalog + return Response(status=204) + + def _find_next_relevant_page(self, page, direction): + """ + Helper method to find the next page that meets conditions. + :param page: current page object + :param direction: 'next' or 'prev' direction for navigation + :return: next relevant page or None if no further page meets conditions + """ + while True: + if direction == 'prev': + next_page = self.project.catalog.get_prev_page(page) else: next_page = self.project.catalog.get_next_page(page) - if next_page is not None: - url = reverse('v1-projects:project-page-detail', args=[self.project.id, next_page.id]) - return HttpResponseRedirect(url, status=303) - # indicate end of catalog - return Response(status=204) + # Break the loop if no more pages are available + if not next_page: + return None + + # Check if the next page meets conditions + conditions = next_page.conditions.select_related('source', 'target_option') + values = self.project.values.filter(snapshot=None).select_related('attribute', 'option') + if check_conditions(conditions, values): + return next_page # Found the final target page + + # Move to the next page in the loop + page = next_page @action(detail=False, url_path='continue', permission_classes=(HasModelPermission | HasProjectPagePermission, )) def get_continue(self, request, pk=None, parent_lookup_project=None):