예제 #1
0
    def get_queryset(self):
        """
        Overrides queryset.

        Shows feedback for studies you can edit, or feedback left on your created responses.
        A researcher can only add feedback to responses to studies they have permission to
        edit feedback for.
        """
        qs = super().get_queryset()

        studies_for_data = studies_for_which_user_has_perm(
            self.request.user, StudyPermission.READ_STUDY_RESPONSE_DATA
        ).values_list("id", flat=True)
        studies_for_preview = studies_for_which_user_has_perm(
            self.request.user, StudyPermission.READ_STUDY_PREVIEW_DATA
        ).values_list("id", flat=True)
        consented_responses = get_consented_responses_qs().filter(
            (Q(study__id__in=studies_for_data) & Q(is_preview=False))
            | (Q(study__id__in=studies_for_preview) & Q(is_preview=True))
        )
        response_ids = consented_responses.values_list("id", flat=True)
        return qs.filter(
            Q(response__id__in=response_ids)
            | Q(response__child__user=self.request.user)
        ).distinct()
예제 #2
0
    def get_queryset(self):
        """
        Overrides queryset.

        Shows 1) users that have responded to studies you can view and 2) your own user object
        """
        all_users = super().get_queryset()
        # Users with can_read_all_user_data permissions can view all active users via the API
        if self.request.user.has_perm("accounts.can_read_all_user_data"):
            return all_users.filter(is_active=True)
        qs_ids = all_users.values_list("id", flat=True)

        studies_for_data = studies_for_which_user_has_perm(
            self.request.user, StudyPermission.READ_STUDY_RESPONSE_DATA
        ).values_list("id", flat=True)
        studies_for_preview = studies_for_which_user_has_perm(
            self.request.user, StudyPermission.READ_STUDY_PREVIEW_DATA
        ).values_list("id", flat=True)
        consented_responses = get_consented_responses_qs().filter(
            (Q(study__id__in=studies_for_data) & Q(is_preview=False))
            | (Q(study__id__in=studies_for_preview) & Q(is_preview=True))
        )

        child_ids = consented_responses.values_list("child", flat=True)
        return User.objects.filter(
            (Q(children__id__in=child_ids) | Q(id=self.request.user.id)),
            Q(id__in=qs_ids),
        ).distinct()
예제 #3
0
    def get_queryset(self):
        """
        Overrides queryset.

        Show children that have 1) responded to studies you can view and 2) are your own children
        """
        children_for_active_users = super().get_queryset()
        # Users with can_read_all_user_data permissions can view all children/demographics of active users via the API
        if self.request.user.has_perm("accounts.can_read_all_user_data"):
            return children_for_active_users

        # TODO: make helper for this, maybe on user
        studies_for_data = studies_for_which_user_has_perm(
            self.request.user, StudyPermission.READ_STUDY_RESPONSE_DATA
        ).values_list("id", flat=True)
        studies_for_preview = studies_for_which_user_has_perm(
            self.request.user, StudyPermission.READ_STUDY_PREVIEW_DATA
        ).values_list("id", flat=True)
        consented_responses = get_consented_responses_qs().filter(
            (Q(study__id__in=studies_for_data) & Q(is_preview=False))
            | (Q(study__id__in=studies_for_preview) & Q(is_preview=True))
        )

        child_ids = consented_responses.values_list("child", flat=True)

        return children_for_active_users.filter(
            (Q(id__in=child_ids) | Q(user__id=self.request.user.id))
        )
예제 #4
0
    def get_queryset(self):
        """Queryset getter override.

        Largely duplicated from ChildViewSet but not completely, so we should duplicate before introducing the wrong
        abstraction.

        :return: The properly configured queryset.
        """
        demographics_for_active_users = super().get_queryset()

        if self.request.user.has_perm("accounts.can_read_all_user_data"):
            return demographics_for_active_users

        studies_for_data = studies_for_which_user_has_perm(
            self.request.user, StudyPermission.READ_STUDY_RESPONSE_DATA
        ).values_list("id", flat=True)
        studies_for_preview = studies_for_which_user_has_perm(
            self.request.user, StudyPermission.READ_STUDY_PREVIEW_DATA
        ).values_list("id", flat=True)
        consented_responses = get_consented_responses_qs().filter(
            (Q(study__id__in=studies_for_data) & Q(is_preview=False))
            | (Q(study__id__in=studies_for_preview) & Q(is_preview=True))
        )

        demographics_ids = consented_responses.values_list(
            "demographic_snapshot", flat=True
        )

        return demographics_for_active_users.filter(
            (Q(id__in=demographics_ids) | Q(user__id=self.request.user.id))
        )
예제 #5
0
 def valid_responses(self):
     study_ids_real_data = studies_for_which_user_has_perm(
         self.request.user,
         StudyPermission.READ_STUDY_RESPONSE_DATA).values_list("id",
                                                               flat=True)
     study_ids_preview_data = studies_for_which_user_has_perm(
         self.request.user,
         StudyPermission.READ_STUDY_PREVIEW_DATA).values_list("id",
                                                              flat=True)
     return get_consented_responses_qs().filter(
         Q(study__id__in=study_ids_real_data, is_preview=False)
         | Q(study__id__in=study_ids_preview_data, is_preview=True))
예제 #6
0
    def get_queryset(self):
        """
        Restricts queryset to participants that a researcher has permission to view.
        """
        studies = get_objects_for_user(self.request.user,
                                       "studies.can_view_study")
        valid_study_ids = studies.values_list("id", flat=True)
        valid_child_ids = (get_consented_responses_qs().filter(
            study__id__in=valid_study_ids).values_list("child", flat=True))

        return (User.objects.filter(
            children__in=valid_child_ids).prefetch_related(
                Prefetch("children",
                         queryset=Child.objects.filter(
                             id__in=valid_child_ids))).distinct())
예제 #7
0
    def get_queryset(self):
        """
        Overrides queryset.

        Show children that have 1) responded to studies you can view and 2) are your own children
        """
        children_for_active_users = super().get_queryset()
        # Users with can_read_all_user_data permissions can view all children/demographics of active users via the API
        if self.request.user.has_perm("accounts.can_read_all_user_data"):
            return children_for_active_users

        studies = get_objects_for_user(self.request.user,
                                       "studies.can_view_study_responses")

        consented_responses = get_consented_responses_qs().filter(
            study__in=studies)

        child_ids = consented_responses.values_list("child", flat=True)

        return children_for_active_users.filter(
            (Q(id__in=child_ids) | Q(user__id=self.request.user.id)))
예제 #8
0
 def get_study_info(self):
     """
     Returns paginated responses from a user with the study title, response
     id, completion status, and date modified.
     """
     resps = (
         get_consented_responses_qs()
         .filter(child__user=self.get_object())
         .select_related("child__user")
     )
     orderby = self.request.GET.get("sort", "-date_created")
     if orderby:
         if "date_created" in orderby:
             resps = resps.order_by(orderby)
         elif "completed" in orderby:
             resps = resps.order_by(
                 orderby.replace("-", "") if "-" in orderby else "-" + orderby
             )
     studies = [
         {
             "modified": resp.date_modified,
             "created": resp.date_created,
             "study": resp.study,
             "name": resp.study.name,
             "completed": resp.completed,
             "response": resp,
         }
         for resp in resps
     ]
     if orderby and "name" in orderby:
         studies = sorted(
             studies,
             key=operator.itemgetter("name"),
             reverse=True if "-" in orderby else False,
         )
     return self.paginated_queryset(studies, self.request.GET.get("page"), 10)
예제 #9
0
    def get_queryset(self):
        """Queryset getter override.

        Largely duplicated from ChildViewSet but not completely, so we should duplicate before introducing the wrong
        abstraction.

        :return: The properly configured queryset.
        """
        demographics_for_active_users = super().get_queryset()

        if self.request.user.has_perm("accounts.can_read_all_user_data"):
            return demographics_for_active_users

        studies = get_objects_for_user(self.request.user,
                                       "studies.can_view_study_responses")

        consented_responses = get_consented_responses_qs().filter(
            study__in=studies)

        demographics_ids = consented_responses.values_list(
            "demographic_snapshot", flat=True)

        return demographics_for_active_users.filter(
            (Q(id__in=demographics_ids) | Q(user__id=self.request.user.id)))
예제 #10
0
    def get_queryset(self):
        """Overrides queryset.

        The overall idea is that we want to limit the responses one can retrieve through the API to two cases:
        1) A user is in a session in the frameplayer, and they're hitting the response API to update their session.
        2) A researcher is programmatically accessing the API to get responses for a given study

        XXX: HERE BE DRAGONS: this method is invoked with PATCH as well as GET requests!
        TODO: Break this out into multiple handlers. The logic-gymnastics is getting annoying.
        """
        children_belonging_to_user = Child.objects.filter(user__id=self.request.user.id)

        # NESTED ROUTE:
        # GET /api/v1/studies/{STUDY_ID}/responses/?{Query string with pagination and child id}
        # This route gets accessed by:
        #     1) Participant sessions GETting history of responses for a study and a given child.
        #     2) Experimenters/parents programmatically GETting the responses facet of the *Study*
        #        API to retrieve responses for a given study.
        if "study_uuid" in self.kwargs:
            study_uuid = self.kwargs["study_uuid"]
            study = get_object_or_404(Study, uuid=study_uuid)

            nested_responses = study.responses

            # CASE 1: Participant session, using query string with child ID.
            # Want same functionality regardless of whether user is a researcher.
            child_id = self.request.query_params.get("child", None)
            if child_id == "TEST_CHILD_DISREGARD":
                return Response.objects.none()  # Preview route
            elif child_id is not None:
                nested_responses = nested_responses.filter(
                    child__uuid=child_id, child__in=children_belonging_to_user
                )

            # CASE 2: Experimenters/parents getting responses for study.
            else:
                if self.request.user.has_study_perms(
                    StudyPermission.READ_STUDY_RESPONSE_DATA, study
                ) or self.request.user.has_study_perms(
                    StudyPermission.READ_STUDY_PREVIEW_DATA, study
                ):
                    consented_responses = study.responses_for_researcher(
                        self.request.user
                    )  # consented preview/real responses as appropriate
                    nested_responses = nested_responses.filter(
                        Q(pk__in=consented_responses)
                        | Q(child__in=children_belonging_to_user)
                    ).select_related(
                        "child",
                        "child__user",
                        "study",
                        "study__study_type",
                        "demographic_snapshot",
                    )
                else:
                    nested_responses = nested_responses.filter(
                        child__in=children_belonging_to_user
                    )

            # Order by date created even though in some edge cases the current session will
            # not be the most recently created (e.g., same user made an additional attempt to
            # participate after starting this session) - updating
            # consent status will change date_modified
            return nested_responses.order_by("-date_modified")

        else:  # NON-NESTED ROUTE
            # GET '/api/v1/responses/' or PATCH '/api/v1/responses/{RESPONSE_UUID}'.
            # This route gets accessed by:
            #     1) Participant sessions PATCHing (partial updating) ongoing response-sessions.
            #     2) Experimenters/parents programmatically GETting the Responses API

            studies_for_data = studies_for_which_user_has_perm(
                self.request.user, StudyPermission.READ_STUDY_RESPONSE_DATA
            ).values_list("id", flat=True)
            studies_for_preview = studies_for_which_user_has_perm(
                self.request.user, StudyPermission.READ_STUDY_PREVIEW_DATA
            ).values_list("id", flat=True)
            consented_responses = get_consented_responses_qs().filter(
                (Q(study__id__in=studies_for_data) & Q(is_preview=False))
                | (Q(study__id__in=studies_for_preview) & Q(is_preview=True))
            )

            response_queryset = Response.objects.filter(
                Q(child__in=children_belonging_to_user)  # Case #1
                | Q(pk__in=consented_responses)  # Case #2
            ).select_related(
                "child",
                "child__user",
                "study",
                "study__study_type",
                "demographic_snapshot",
            )

            return response_queryset.order_by("-date_modified")