Exemplo n.º 1
0
    def __init__(self, _type, fields=None, extra_filter_meta=None,
                 filterset_class=None, *args, **kwargs):

        if DJANGO_FILTER_INSTALLED:
            _fields = _type._meta.filter_fields
            _model = _type._meta.model

            self.fields = fields or _fields
            meta = dict(model=_model, fields=self.fields)
            if extra_filter_meta:
                meta.update(extra_filter_meta)
            filterset_class = filterset_class or _type._meta.filterset_class
            self.filterset_class = get_filterset_class(filterset_class, **meta)
            self.filtering_args = get_filtering_args_from_filterset(self.filterset_class, _type)
            kwargs.setdefault('args', {})
            kwargs['args'].update(self.filtering_args)

            if 'id' not in kwargs['args'].keys():
                self.filtering_args.update({'id': Argument(ID,
                                                           description='Django object unique identification field')})
                kwargs['args'].update({
                    'id': Argument(ID, description='Django object unique identification field')
                })

        if not kwargs.get('description', None):
            kwargs['description'] = '{} list'.format(
                _type._meta.model.__name__
            )

        super(DjangoFilterListField, self).__init__(
            List(_type), *args, **kwargs
        )
Exemplo n.º 2
0
class ProjectByRegionGqlFilterSet(django_filters.FilterSet):
    RegionProjectFilterData = type(
        'RegionProjectFilterData',
        (graphene.InputObjectType,),
        get_filtering_args_from_filterset(ProjectGqlFilterSet, 'project.schema.ProjectListType')
    )

    project_filter = SimpleInputFilter(RegionProjectFilterData, method='filter_project_filter')

    class Meta:
        model = Region
        fields = ()

    def filter_project_filter(self, qs, *_):
        # Used in def qs
        return qs

    def get_project_queryset(self):
        return Project.get_for_gq(self.request.user)

    @property
    def qs(self):
        project_qs = self.get_project_queryset()
        # Filter project if filter is provided
        project_filter = self.data.get('project_filter')
        if project_filter:
            project_qs = ProjectGqlFilterSet(data=project_filter, queryset=project_qs, request=self.request).qs
        return super().qs.annotate(
            projects_id=ArrayAgg('project', distinct=True, ordering='project', filter=models.Q(project__in=project_qs)),
        ).filter(projects_id__isnull=False).only('id', 'centroid')
Exemplo n.º 3
0
def generate_list_search_parameters(schema_type):
    """Generate list of query parameters for the list resolver based on a filterset."""

    search_params = {}
    if schema_type._meta.filterset_class is not None:
        # We need an instance for custom fields generation to happen for the
        # filterset_class or the `cf_*` fields won't be detected.
        filterset = schema_type._meta.filterset_class()
        # Patch base_filters because `get_filtering_args_from_filterset` looks there
        filterset.base_filters = filterset.filters

        search_params = get_filtering_args_from_filterset(
            filterset,
            schema_type,
        )

    # Hack to swap `type` fields to `_type` since they will conflict with
    # `graphene.types.fields.Field.type` in Graphene 2.x.
    # TODO(jathan): Once we upgrade to Graphene 3.x we can remove this, but we
    # will still need to do an API migration to deprecate it. This argument was
    # validated to be safe to keep even in Graphene 3.
    if "type" in search_params:
        search_params["_type"] = search_params.pop("type")

    return search_params
Exemplo n.º 4
0
    def __init__(
        self,
        _type,
        pagination=None,
        fields=None,
        extra_filter_meta=None,
        filterset_class=None,
        *args,
        **kwargs,
    ):

        _fields = _type._meta.filter_fields
        _model = _type._meta.model

        self.fields = fields or _fields
        meta = dict(model=_model, fields=self.fields)
        if extra_filter_meta:
            meta.update(extra_filter_meta)

        filterset_class = filterset_class or _type._meta.filterset_class
        self.filterset_class = get_filterset_class(filterset_class, **meta)
        self.filtering_args = get_filtering_args_from_filterset(
            self.filterset_class, _type)
        kwargs.setdefault("args", {})
        kwargs["args"].update(self.filtering_args)

        if "id" not in kwargs["args"].keys():
            self.filtering_args.update({
                "id":
                Argument(
                    ID,
                    description="Django object unique identification field")
            })
            kwargs["args"].update({
                "id":
                Argument(
                    ID,
                    description="Django object unique identification field")
            })

        pagination = pagination or graphql_api_settings.DEFAULT_PAGINATION_CLASS(
        )

        if pagination is not None:
            assert isinstance(pagination, BaseDjangoGraphqlPagination), (
                'You need to pass a valid DjangoGraphqlPagination in DjangoFilterPaginateListField, received "{}".'
            ).format(pagination)

            pagination_kwargs = pagination.to_graphql_fields()

            self.pagination = pagination
            kwargs.update(**pagination_kwargs)

        if not kwargs.get("description", None):
            kwargs["description"] = "{} list".format(
                _type._meta.model.__name__)

        super(DjangoFilterPaginateListField,
              self).__init__(List(_type), *args, **kwargs)
Exemplo n.º 5
0
    def __init__(self,
                 _type,
                 pagination=None,
                 fields=None,
                 extra_filter_meta=None,
                 filterset_class=None,
                 preprocess_kwargs=None,
                 *args,
                 **kwargs):

        _fields = _type._meta.filter_fields
        _model = _type._meta.model

        self.fields = fields or _fields
        meta = dict(model=_model, fields=self.fields)
        if extra_filter_meta:
            meta.update(extra_filter_meta)
        self.filterset_class = get_filterset_class(filterset_class, **meta)
        self.filtering_args = get_filtering_args_from_filterset(
            self.filterset_class, _type)
        kwargs.setdefault('args', {})
        kwargs['args'].update(self.filtering_args)

        if 'id' not in kwargs['args'].keys():
            self.filtering_args.update({
                'id':
                Argument(
                    ID,
                    description='Django object unique identification field')
            })
            kwargs['args'].update({
                'id':
                Argument(
                    ID,
                    description='Django object unique identification field')
            })

        pagination = pagination or graphql_api_settings.DEFAULT_PAGINATION_CLASS

        if pagination is not None:
            assert isinstance(pagination, BaseDjangoGraphqlPagination), (
                'You need to pass a valid DjangoGraphqlPagination in DjangoFilterPaginateListField, received "{}".'
            ).format(pagination)

            pagination_kwargs = list_pagination_factory(pagination)

            self.pagination = pagination
            kwargs.update(**pagination_kwargs)

        if not kwargs.get('description', None):
            kwargs['description'] = '{} list'.format(
                _type._meta.model.__name__)

        preprocess_kwargs = preprocess_kwargs or kwargs_formatter
        kwargs = preprocess_kwargs(**kwargs)

        super(DjangoFilterPaginateListField,
              self).__init__(List(_type), *args, **kwargs)
Exemplo n.º 6
0
 def __init__(self, _type, fields=None, extra_filter_meta=None,
              filterset_class=None, *args, **kwargs):
     _fields = _type._meta.filter_fields
     _model = _type._meta.model
     self._model = _type._meta.model
     self.fields = fields or _fields
     meta = dict(model=_model, fields=self.fields)
     self.filterset_class = get_filterset_class(filterset_class, **meta)
     self.filtering_args = get_filtering_args_from_filterset(
         self.filterset_class, _type)
     self._base_args = None
     super().__init__(List(_type), *args, **kwargs)
Exemplo n.º 7
0
    def __init__(self,
                 _type,
                 pagination=None,
                 fields=None,
                 extra_filter_meta=None,
                 filterset_class=None,
                 preprocess_kwargs=None,
                 *args,
                 **kwargs):

        _fields = _type._meta.filter_fields
        _model = _type._meta.model

        self.fields = fields or _fields
        meta = dict(model=_model, fields=self.fields)
        if extra_filter_meta:
            meta.update(extra_filter_meta)
        self.filterset_class = get_filterset_class(filterset_class, **meta)
        self.filtering_args = get_filtering_args_from_filterset(
            self.filterset_class, _type)
        kwargs.setdefault('args', {})
        kwargs['args'].update(self.filtering_args)

        if 'id' not in kwargs['args'].keys():
            self.filtering_args.update({
                'id':
                Argument(
                    ID,
                    description='Django object unique identification field')
            })
            kwargs['args'].update({
                'id':
                Argument(
                    ID,
                    description='Django object unique identification field')
            })

        if pagination:
            pagination_kwargs = list_pagination_factory(pagination)

            self.pagination = pagination
            kwargs.update(**pagination_kwargs)

        if not kwargs.get('description', None):
            kwargs['description'] = '{} list'.format(
                _type._meta.model.__name__)

        preprocess_kwargs = preprocess_kwargs or kwargs_formatter
        kwargs = preprocess_kwargs(**kwargs)

        super(DjangoFilterPaginateListField,
              self).__init__(List(_type), *args, **kwargs)
Exemplo n.º 8
0
    def __init__(self,
                 _type,
                 permission_classes=(),
                 output_type=None,
                 fields=None,
                 extra_filter_meta=None,
                 filterset_class=None,
                 skip_filters=False,
                 *args,
                 **kwargs):
        self.filterset_class = {}
        self.filtering_args = {}

        assert isinstance(
            permission_classes,
            (tuple,
             list)), ("Permissions can only be a `List` of `Tuple` - ".format(
                 self.__class__.__name__))

        self.permission_classes = permission_classes

        if DJANGO_FILTER_INSTALLED and not skip_filters:
            _fields = _type._meta.filter_fields
            _model = _type._meta.model

            self.fields = fields or _fields
            meta = dict(model=_model, fields=self.fields)
            if extra_filter_meta:
                meta.update(extra_filter_meta)
            filterset_class = filterset_class or _type._meta.filterset_class
            self.filterset_class = get_filterset_class(filterset_class, **meta)
            self.filtering_args = get_filtering_args_from_filterset(
                self.filterset_class, _type)
            kwargs.setdefault("args", {})
            kwargs["args"].update(self.filtering_args)

            if "id" not in kwargs["args"].keys():
                kwargs["args"].update({
                    "id":
                    Argument(
                        ID,
                        description="Django object unique identification field"
                    )
                })
        if not kwargs.get("description", None):
            kwargs["description"] = "{} list".format(
                _type._meta.model.__name__)
        self.skip_filters = skip_filters
        super(DjangoBaseListField, self).__init__(output_type or _type, *args,
                                                  **kwargs)
Exemplo n.º 9
0
    def __init__(
        self,
        _type,
        pagination=None,
        fields=None,
        extra_filter_meta=None,
        filterset_class=None,
        *args,
        **kwargs,
    ):
        '''
        If pagination is None, then we will only allow Ordering fields.
            - The page size will respect the settings.
            - Client will not be able to add pagination params
        '''
        _fields = _type._meta.filter_fields
        _model = _type._meta.model

        self.fields = fields or _fields
        meta = dict(model=_model, fields=self.fields)
        if extra_filter_meta:
            meta.update(extra_filter_meta)

        filterset_class = filterset_class or _type._meta.filterset_class
        self.filterset_class = get_filterset_class(filterset_class, **meta)
        self.filtering_args = get_filtering_args_from_filterset(
            self.filterset_class, _type)
        kwargs.setdefault("args", {})
        kwargs["args"].update(self.filtering_args)

        pagination = pagination or OrderingOnlyArgumentPagination()

        if pagination is not None:
            assert isinstance(pagination, BaseDjangoGraphqlPagination), (
                'You need to pass a valid DjangoGraphqlPagination in DjangoFilterPaginateListField, received "{}".'
            ).format(pagination)

            pagination_kwargs = pagination.to_graphql_fields()

            self.pagination = pagination
            kwargs.update(**pagination_kwargs)

        if not kwargs.get("description", None):
            kwargs["description"] = "{} list".format(
                _type._meta.model.__name__)

        # accessor will be used with m2m or reverse_fk fields
        self.accessor = kwargs.pop('accessor', None)
        super(DjangoFilterPaginateListField,
              self).__init__(_type, *args, **kwargs)
Exemplo n.º 10
0
    def __init__(self, _type, fields=None, extra_filter_meta=None,
                 filterset_class=None, *args, **kwargs):

        _fields = _type._meta.filter_fields
        _model = _type._meta.model

        self.fields = fields or _fields
        meta = dict(model=_model, fields=self.fields)
        if extra_filter_meta:
            meta.update(extra_filter_meta)
        self.filterset_class = get_filterset_class(filterset_class, **meta)
        self.filtering_args = get_filtering_args_from_filterset(self.filterset_class, _type)
        kwargs.setdefault('args', {})
        kwargs['args'].update(self.filtering_args)
        super().__init__(List(_type), *args, **kwargs)
Exemplo n.º 11
0
    def get_filter_args(self, _type, kwargs, inner_field=None):
        self.filterset_class = get_filterset_class(
            getattr(_type._meta, 'filterset_class', None),
            model=_type._meta.model,
            fields=_type._meta.filter_fields,
        )

        self.filtering_args = get_filtering_args_from_filterset(
            self.filterset_class, _type)
        kwargs.setdefault('args', {})

        order_args = {
            to_camel_case(k): i
            for (i, k) in enumerate(set(_type._meta.order_fields + ['id']))
        }

        if len(order_args.items()) == 0:
            raise Exception(f'No ordering args found on {_type}')

        order_by_enum = enum.Enum(
            f'{_type}_{inner_field.model.__name__}_{inner_field.name}_OrderingFilter'
            if inner_field else f'{_type}OrderingFilter', order_args)
        self.order_by_enum = order_by_enum

        OrderByEnumObject = type(
            order_by_enum.__name__ + 'Object', (graphene.InputObjectType, ), {
                'field':
                graphene.Enum.from_enum(order_by_enum)(),
                'direction':
                OrderingDirectionEnumType(
                    default_value=OrderingDirectionEnum.ASC.value),
                'modifiers':
                graphene.List(OrderingModifierEnumType, default_value=[]),
            })

        kwargs['args']['order_by'] = graphene.List(OrderByEnumObject,
                                                   default_value=[],
                                                   name='orderBy').Argument()
        kwargs['args']['limit'] = graphene.Int(default_value=0,
                                               name='limit').Argument()
        kwargs['args']['offset'] = graphene.Int(default_value=0,
                                                name='offset').Argument()
        kwargs['args'].update(self.filtering_args)
        return kwargs
Exemplo n.º 12
0
    def __init__(
        self,
        _type,
        fields=None,
        extra_filter_meta=None,
        filterset_class=None,
        *args,
        **kwargs,
    ):

        if DJANGO_FILTER_INSTALLED:
            _fields = _type._meta.filter_fields
            _model = _type._meta.model

            self.fields = fields or _fields

            meta = dict(model=_model, fields=self.fields)
            if extra_filter_meta:
                meta.update(extra_filter_meta)

            filterset_class = filterset_class or _type._meta.filterset_class
            self.filterset_class = get_filterset_class(filterset_class, **meta)
            self.filtering_args = get_filtering_args_from_filterset(
                self.filterset_class, _type)
            kwargs.setdefault("args", {})
            kwargs["args"].update(self.filtering_args)

            if "id" not in kwargs["args"].keys():
                id_description = "Django object unique identification field"
                self.filtering_args.update(
                    {"id": Argument(ID, description=id_description)})
                kwargs["args"].update(
                    {"id": Argument(ID, description=id_description)})

        if not kwargs.get("description", None):
            kwargs["description"] = "{} list".format(
                _type._meta.model.__name__)

        super(DjangoListObjectField, self).__init__(_type, *args, **kwargs)
Exemplo n.º 13
0
    def __init__(self, _type, pagination=None, fields=None, extra_filter_meta=None,
                 filterset_class=None, *args, **kwargs):

        _fields = _type._meta.filter_fields
        _model = _type._meta.model

        self.fields = fields or _fields
        meta = dict(model=_model, fields=self.fields)
        if extra_filter_meta:
            meta.update(extra_filter_meta)

        filterset_class = filterset_class or _type._meta.filterset_class
        self.filterset_class = get_filterset_class(filterset_class, **meta)
        self.filtering_args = get_filtering_args_from_filterset(self.filterset_class, _type)
        kwargs.setdefault('args', {})
        kwargs['args'].update(self.filtering_args)

        if 'id' not in kwargs['args'].keys():
            self.filtering_args.update({'id': Argument(ID, description='Django object unique identification field')})
            kwargs['args'].update({'id': Argument(ID, description='Django object unique identification field')})

        pagination = pagination or graphql_api_settings.DEFAULT_PAGINATION_CLASS()

        if pagination is not None:
            assert isinstance(pagination, BaseDjangoGraphqlPagination), (
                'You need to pass a valid DjangoGraphqlPagination in DjangoFilterPaginateListField, received "{}".'
            ).format(pagination)

            pagination_kwargs = pagination.to_graphql_fields()

            self.pagination = pagination
            kwargs.update(**pagination_kwargs)

        if not kwargs.get('description', None):
            kwargs['description'] = '{} list'.format(_type._meta.model.__name__)

        super(DjangoFilterPaginateListField, self).__init__(List(_type), *args, **kwargs)
Exemplo n.º 14
0
    def __init__(
        self,
        _type,
        pagination=None,
        fields=None,
        extra_filter_meta=None,
        filterset_class=None,
        *args,
        **kwargs,
    ):

        _fields = _type._meta.filter_fields
        _model = _type._meta.model

        self.fields = fields or _fields
        meta = dict(model=_model, fields=self.fields)
        if extra_filter_meta:
            meta.update(extra_filter_meta)

        filterset_class = filterset_class or _type._meta.filterset_class
        self.filterset_class = get_filterset_class(filterset_class, **meta)
        self.filtering_args = get_filtering_args_from_filterset(
            self.filterset_class, _type)
        kwargs.setdefault("args", {})
        kwargs["args"].update(self.filtering_args)
        """
        # filtering by primary key or id seems unnecessary...
        if "id" not in kwargs["args"].keys():
            self.filtering_args.update(
                {
                    "id": Argument(
                        ID, description="Django object unique identification field"
                    )
                }
            )
            kwargs["args"].update(
                {
                    "id": Argument(
                        ID, description="Django object unique identification field"
                    )
                }
            )
        """

        pagination = pagination or OrderingOnlyArgumentPagination()

        if pagination is not None:
            assert isinstance(pagination, BaseDjangoGraphqlPagination), (
                'You need to pass a valid DjangoGraphqlPagination in DjangoFilterPaginateListField, received "{}".'
            ).format(pagination)

            pagination_kwargs = pagination.to_graphql_fields()

            self.pagination = pagination
            kwargs.update(**pagination_kwargs)

        if not kwargs.get("description", None):
            kwargs["description"] = "{} list".format(
                _type._meta.model.__name__)

        # accessor will be used with m2m or reverse_fk fields
        self.accessor = kwargs.pop('accessor', None)
        super(DjangoFilterPaginateListField,
              self).__init__(_type, *args, **kwargs)
Exemplo n.º 15
0
class LeadGQFilterSet(UserResourceGqlFilterSet):
    ids = IDListFilter(method='filter_leads_id', help_text='Empty ids are ignored.')
    exclude_provided_leads_id = django_filters.BooleanFilter(
        method='filter_exclude_provided_leads_id', help_text='Only used when ids are provided.')
    created_by = IDListFilter()
    modified_by = IDListFilter()
    source_types = MultipleInputFilter(LeadSourceTypeEnum, field_name='source_type')
    priorities = MultipleInputFilter(LeadPriorityEnum, field_name='priority')
    confidentiality = SimpleInputFilter(LeadConfidentialityEnum)
    statuses = MultipleInputFilter(LeadStatusEnum, field_name='status')
    extraction_status = SimpleInputFilter(LeadExtractionStatusEnum, field_name='extraction_status')
    assignees = IDListFilter(field_name='assignee')
    authoring_organization_types = IDListFilter(method='authoring_organization_types_filter')
    author_organizations = IDListFilter(method='authoring_organizations_filter')
    source_organizations = IDListFilter(method='source_organizations_filter')
    # Filter-only enum filter
    has_entries = django_filters.BooleanFilter(method='filter_has_entries', help_text='Lead has entries.')
    has_assessment = django_filters.BooleanFilter(method='filter_has_assessment', help_text='Lead has assessment.')
    entries_filter_data = SimpleInputFilter(
        type(
            'LeadEntriesFilterData',
            (graphene.InputObjectType,),
            get_filtering_args_from_filterset(EntryGQFilterSet, 'entry.schema.EntryListType')
        ),
        method='filtered_entries_filter_data',
    )

    search = django_filters.CharFilter(method='search_filter')

    published_on = django_filters.DateFilter()
    published_on_gte = DateGteFilter(field_name='published_on')
    published_on_lte = DateLteFilter(field_name='published_on')

    emm_entities = django_filters.CharFilter(method='emm_entities_filter')
    emm_keywords = django_filters.CharFilter(method='emm_keywords_filter')
    emm_risk_factors = django_filters.CharFilter(method='emm_risk_factors_filter')

    ordering = MultipleInputFilter(LeadOrderingEnum, method='ordering_filter')

    class Meta:
        model = Lead
        fields = {
            **{
                x: ['exact']
                for x in ['text', 'url']
            },
        }

        filter_overrides = {
            models.CharField: {
                'filter_class': django_filters.CharFilter,
                'extra': lambda _: {
                    'lookup_expr': 'icontains',
                },
            },
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.custom_context = {}

    @property
    def active_project(self) -> Project:
        if self.request is None:
            raise Exception(f'{self.request=} should be defined')
        if self.request.active_project is None:
            raise Exception(f'{self.request.active_project=} should be defined')
        return self.request.active_project

    @staticmethod
    def get_dummy_request(project):
        """
        Use this if request is not available
        """
        return type('DummyRequest', (object,), dict(active_project=project))()

    # Filters methods
    def search_filter(self, qs, name, value):
        # NOTE: This exists to make it compatible with post filter
        if not value:
            return qs
        return qs.filter(
            # By title
            models.Q(title__icontains=value) |
            # By source
            models.Q(source_raw__icontains=value) |
            models.Q(source__title__icontains=value) |
            models.Q(source__parent__title__icontains=value) |
            # By author
            models.Q(author__title__icontains=value) |
            models.Q(author__parent__title__icontains=value) |
            models.Q(author_raw__icontains=value) |
            models.Q(authors__title__icontains=value) |
            models.Q(authors__parent__title__icontains=value) |
            # By URL
            models.Q(url__icontains=value)
        ).distinct()

    def ordering_filter(self, qs, name, value):
        active_entry_count_field = self.custom_context.get('active_entry_count_field')
        for ordering in value:
            # Custom for entries count (use filter or normal entry count)
            if active_entry_count_field and ordering in [
                LeadOrderingEnum.ASC_ENTRIES_COUNT,
                LeadOrderingEnum.DESC_ENTRIES_COUNT,
            ]:
                if ordering == LeadOrderingEnum.ASC_ENTRIES_COUNT:
                    qs = qs.order_by(active_entry_count_field)
                else:
                    qs = qs.order_by(f'-{active_entry_count_field}')
            # Custom for page count with nulls_last
            elif ordering == LeadOrderingEnum.DESC_PAGE_COUNT:
                qs = qs.order_by(models.F('leadpreview__page_count').desc(nulls_last=True))
            elif ordering == LeadOrderingEnum.ASC_PAGE_COUNT:
                qs = qs.order_by(models.F('leadpreview__page_count').asc(nulls_first=True))
            # For remaining
            else:
                qs = qs.order_by(ordering)
        return qs

    def emm_entities_filter(self, qs, name, value):
        splitted = [x for x in value.split(',') if x]
        return qs.filter(emm_entities__in=splitted)

    def emm_keywords_filter(self, qs, name, value):
        splitted = [x for x in value.split(',') if x]
        return qs.filter(emm_triggers__emm_keyword__in=splitted)

    def emm_risk_factors_filter(self, qs, name, value):
        splitted = [x for x in value.split(',') if x]
        return qs.filter(emm_triggers__emm_risk_factor__in=splitted)

    def authoring_organization_types_filter(self, qs, name, value):
        if value:
            qs = qs.annotate(
                organization_types=Coalesce(
                    'authors__parent__organization_type',
                    'authors__organization_type'
                )
            )
            if type(value[0]) == OrganizationType:
                return qs.filter(organization_types__in=[ot.id for ot in value]).distinct()
            return qs.filter(organization_types__in=value).distinct()
        return qs

    def authoring_organizations_filter(self, qs, _, value):
        if value:
            qs = qs.annotate(authoring_organizations=Coalesce('authors__parent_id', 'authors__id'))
            return qs.filter(authoring_organizations__in=value).distinct()
        return qs

    def source_organizations_filter(self, qs, _, value):
        if value:
            qs = qs.annotate(source_organizations=Coalesce('source__parent_id', 'source__id'))
            return qs.filter(source_organizations__in=value).distinct()
        return qs

    def filter_exclude_provided_leads_id(self, qs, *_):
        # NOTE: Used in filter_leads_id
        return qs

    def filter_leads_id(self, qs, _, value):
        if value is None:
            return qs
        if self.data.get('exclude_provided_leads_id'):
            return qs.exclude(id__in=value)
        return qs.filter(id__in=value)

    def filter_has_entries(self, qs, _, value):
        if value is None:
            return qs
        if value:
            return qs.filter(entry_count__gt=0)
        return qs.filter(entry_count=0)

    def filter_has_assessment(self, qs, _, value):
        if value is None:
            return qs
        return qs.filter(assessment__isnull=not value)

    def filtered_entries_filter_data(self, qs, _, value):
        if value is None:
            return qs
        return qs.filter(filtered_entry_count__gt=0)

    def filter_queryset(self, qs):
        def _entry_subquery(entry_qs: models.QuerySet):
            subquery_qs = entry_qs.\
                filter(
                    project=self.active_project,
                    analysis_framework=self.active_project.analysis_framework_id,
                    lead=models.OuterRef('pk'),
                )\
                .values('lead').order_by()\
                .annotate(count=models.Count('id'))\
                .values('count')
            return Coalesce(
                models.Subquery(
                    subquery_qs[:1],
                    output_field=models.IntegerField()
                ), 0,
            )

        # Pre-annotate required fields for entries count (w/wo filters)
        entries_filter_data = self.data.get('entries_filter_data')
        has_entries = self.data.get('has_entries')
        has_entries_count_ordering = any(
            ordering in [
                LeadOrderingEnum.ASC_ENTRIES_COUNT,
                LeadOrderingEnum.DESC_ENTRIES_COUNT,
            ] for ordering in self.data.get('ordering') or []
        )

        # With filter
        if entries_filter_data is not None:
            qs = qs.annotate(
                filtered_entry_count=_entry_subquery(
                    EntryGQFilterSet(
                        data=entries_filter_data,
                        request=self.request,
                    ).qs
                )
            )
            self.custom_context['active_entry_count_field'] = 'filtered_entry_count'
        # Without filter
        if has_entries is not None or (
            entries_filter_data is None and has_entries_count_ordering
        ):
            self.custom_context['active_entry_count_field'] = self.custom_context.\
                get('active_entry_count_field', 'entry_count')
            qs = qs.annotate(
                entry_count=_entry_subquery(Entry.objects.all())
            )
        # Call super function
        return super().filter_queryset(qs)

    @property
    def qs(self):
        return super().qs.distinct()
Exemplo n.º 16
0
class ExportCreateGqlSerializer(ProjectPropertySerializerMixin,
                                serializers.ModelSerializer):
    title = serializers.CharField(required=False)

    class Meta:
        model = Export
        fields = (
            'title',
            'type',  # Data type (entries, assessments, ..)
            'format',  # xlsx, docx, pdf, ...
            'export_type',  # excel, report, json, ...
            'is_preview',
            'filters',
            'analysis',
            # Specific arguments for exports additional configuration
            'excel_decoupled',
            'report_show_groups',
            'report_show_lead_entry_id',
            'report_show_assessment_data',
            'report_show_entry_widget_data',
            'report_text_widget_ids',
            'report_exporting_widgets',
            'report_levels',
            'report_structure',
        )

    # Excel
    excel_decoupled = serializers.BooleanField(
        help_text='Don\'t group entries tags. Slower export generation.',
        required=False)

    # Report
    report_show_groups = serializers.BooleanField(required=False)
    report_show_lead_entry_id = serializers.BooleanField(required=False)
    report_show_assessment_data = serializers.BooleanField(required=False)
    report_show_entry_widget_data = serializers.BooleanField(required=False)
    report_text_widget_ids = serializers.ListField(
        child=serializers.IntegerField(), allow_empty=True, required=False)
    report_exporting_widgets = serializers.ListField(
        child=serializers.IntegerField(), allow_empty=True, required=False)
    report_levels = ExportReportLevelWidgetSerializer(
        required=False,
        many=True,
        help_text=ExportReportLevelWidgetSerializer.__doc__)
    report_structure = ExportReportStructureWidgetSerializer(
        required=False,
        many=True,
        help_text=ExportReportStructureWidgetSerializer.__doc__)

    filters = generate_serializer_field_class(
        type(
            'ExportLeadsEntriesFilterData', (graphene.InputObjectType, ),
            get_filtering_args_from_filterset(LeadGQFilterSet,
                                              'lead.schema.LeadListType')),
        GraphqlSupportDrfSerializerJSONField,
    )()

    @property
    def widget_qs(self):
        return Widget.objects.filter(
            analysis_framework=self.project.analysis_framework_id)

    @property
    def exportable_qs(self):
        return Exportable.objects.filter(
            analysis_framework=self.project.analysis_framework_id)

    def validate_filters(self, filters):
        filter_set = LeadGQFilterSet(data=filters,
                                     request=self.context['request'])
        if not filter_set.is_valid():
            raise serializers.ValidationError(filter_set.errors)
        return filters

    def validate_report_text_widget_ids(self, widget_ids):
        if widget_ids:
            text_widgets_id = self.widget_qs.filter(
                widget_id=Widget.WidgetType.TEXT).values_list('id', flat=True)
            return [
                widget_id for widget_id in widget_ids
                if widget_id in text_widgets_id
            ]
        return []

    def validate_report_exporting_widgets(self, widget_ids):
        if widget_ids:
            widgets_id = self.widget_qs.values_list('id', flat=True)
            return [
                widget_id for widget_id in widget_ids
                if widget_id in widgets_id
            ]
        return []

    # TODO: def validate_report_levels(self, widget_ids):
    # TODO: def validate_report_structure(self, widget_ids):

    def validate_analysis(self, analysis):
        if analysis and analysis.project != self.project:
            raise serializers.ValidationError(
                f'Analysis project {analysis.project_id} doesn\'t match current project {self.project.id}'
            )
        return analysis

    def validate(self, data):
        # NOTE: We only need to check with create logic (as update is not allowed)
        # Validate type, export_type and format
        data_type = data['type']
        export_type = data['export_type']
        _format = data['format']
        if (data_type, export_type, _format) not in Export.DEFAULT_TITLE_LABEL:
            raise serializers.ValidationError(
                f'Unsupported Export request: {(data_type, export_type, _format)}'
            )
        return data

    def update(self, _):
        raise serializers.ValidationError('Update isn\'t allowed for Export')

    def create(self, data):
        data['title'] = data.get('title') or Export.generate_title(
            data['type'], data['export_type'], data['format'])
        data['exported_by'] = self.context['request'].user
        data['project'] = self.project
        data['extra_options'] = {
            key: data.pop(key)
            for key in (
                'excel_decoupled',
                # Report
                'report_show_groups',
                'report_show_lead_entry_id',
                'report_show_assessment_data',
                'report_show_entry_widget_data',
                'report_text_widget_ids',
                'report_exporting_widgets',
                'report_levels',
                'report_structure',
            ) if key in data
        }
        export = super().create(data)
        transaction.on_commit(
            lambda: export.set_task_id(export_task.delay(export.id).id))
        return export
Exemplo n.º 17
0
 def filtering_args(self):
     return get_filtering_args_from_filterset(self.filterset_class,
                                              self.node_type)