Beispiel #1
0
    def dehydrate(self, bundle):
        """
            Override to add in the __label attributes. These are the human readable
            version of attributes that represent objects or more appropriate formatting,
            such as for dates
        :param bundle:
        :return:
        """

        # This is a dynamic field create at the time of creating the FeatureResource subclass
        result_field_lookup = self.result_field_lookup

        # Map the fields that need special human-readable representation
        # to labels. We iterate through the result_field_lookup that
        # the LayerSelection generated for this.
        # Not the conditional statement is for the "corner" case
        # of patching Features with joins specified. Patches always
        # ignore the JoinFeature class and use the regular Feature class,
        # however the result_field_lookup still contains join fields--ignore them
        bundle.data['__labels'] = compact_dict(
            map_dict_to_dict(
                lambda field_name, field_lambda: [
                    field_name,
                    field_lambda(
                        getattr(bundle.obj, self.client_field_name(field_name))
                    )
                ] if '__' not in field_name else None, result_field_lookup))
        return super(FeatureResource, self).dehydrate(bundle)
    def dehydrate(self, bundle):
        """
            Override to add in the __label attributes. These are the human readable
            version of attributes that represent objects or more appropriate formatting,
            such as for dates
        :param bundle:
        :return:
        """

        # This is a dynamic field create at the time of creating the FeatureResource subclass
        result_field_lookup = self.result_field_lookup

        # Map the fields that need special human-readable representation
        # to labels. We iterate through the result_field_lookup that
        # the LayerSelection generated for this.
        # Not the conditional statement is for the "corner" case
        # of patching Features with joins specified. Patches always
        # ignore the JoinFeature class and use the regular Feature class,
        # however the result_field_lookup still contains join fields--ignore them
        bundle.data['__labels'] = compact_dict(map_dict_to_dict(
            lambda field_name, field_lambda: [
                field_name,
                field_lambda(getattr(bundle.obj, self.client_field_name(field_name)))
            ] if '__' not in field_name else None,
            result_field_lookup
        ))
        return super(FeatureResource, self).dehydrate(bundle)
    def test_config_entity_api__permissions(self):
        """
            Make sure that users only get ConfigEntity's that match their permission settings
        :return:
        """

        permission_configuration = TestConfigEntityPermissions.config_entity_configuration()
        resource_name = 'config_entity'

        # Iterate through the test_configurstions and extract a user for each group_key
        # Make a dict with the user as the key and all the instances from the test_config that the
        # user corresponds to. This gives a lookup of a user to the config_entities that we expect
        # the user to be able to view
        # Create a user->instances dict
        # Combine our {user1:instances, user2:instances,...} dicts
        user_to_expected_instances = merge_dict_list_values(
            *map(
                lambda test_configuration:\
                    # Combine our [user, instance] pairs into {user1:instances, user2:instances,...}
                    # Remove null keys (owing to groups with no users)
                    compact_dict(map_to_dict_with_lists(
                        # Each test_configuration has several groups.
                        # For each group resolve a user and return [user, instance]
                        lambda group_key: [
                            get_first_value_or_none(Group.objects.get(name=group_key).user_set.all()),
                            test_configuration['instance']],
                        test_configuration['groups'].keys())),
                permission_configuration.test_configuration)
        )

        all_instances = set(unique(flatten(user_to_expected_instances.values())))
        for user, instances in user_to_expected_instances.items():
            other_instances = all_instances - set(instances)
            # Fetch all instances with this user and create a lookup so we can test
            # that the resulting instances are present or not present as expected according to
            # the permissions
            response = self.get(resource_name, user=user)
            result_instance_lookup = map_to_dict(
                lambda instance_dict: [int(instance_dict['id']), instance_dict],
                self.deserialize(response)['objects'])

            for instance in instances:
                matching_instance = result_instance_lookup.get(instance.id)
                assert_is_not_none(matching_instance,
                                   "User %s should have view permission to instance %s with id %s and key %s but does." % \
                                   (user.username,
                                    instance,
                                    instance.id,
                                    permission_configuration.key_class.Fab.remove(
                                        permission_configuration.instance_key_lambda(instance))))

            for instance in other_instances:
                assert_is_none(matching_instance,
                                   "User %s should not have view permission to instance %s with id %s and key %s but does." % \
                                   (user.username,
                                    instance,
                                    instance.id,
                                    permission_configuration.key_class.Fab.remove(
                                        permission_configuration.instance_key_lambda(instance))))
Beispiel #4
0
 def tables_with_geometry(self, schema=None, table=None):
     """
         Returns tables with a column data type of 'geometry'
     :param schema: Optional schema to search
     :param table: Optional table to which to limit search. This guarantees 0 or 1 result
     :return:
     """
     return self.filter(**merge(dict(udt_name='geometry'),
                                compact_dict(dict(table_schema=schema, table_name=table))))
Beispiel #5
0
 def columns_of_table(self, schema, table, column_name=None):
     """
         Returns the columns matching the given schema, table, and column_name
     :param schema:
     :param table:
     :param column_name: Optionally limit the result to a single value
     :return: The matching InformationSchema instances
     """
     return self.filter(**compact_dict(dict(table_schema=schema, table_name=table, column_name=column_name)))
Beispiel #6
0
 def result_field_extra_sql_lookup(self, query_set):
     """
         Returns a lookup that maps some field names to a lambda that describes
         how to create a human readable form of the field value. This is used by the FeatureResource
     :return:
     """
     return dict(select=compact_dict(
         map_to_dict(self.sql_map_lambda(query_set),
                     self.result_map.result_fields,
                     use_ordered_dict=True)))
 def result_field_extra_sql_lookup(self, query_set):
     """
         Returns a lookup that maps some field names to a lambda that describes
         how to create a human readable form of the field value. This is used by the FeatureResource
     :return:
     """
     return dict(select=compact_dict(map_to_dict(
         self.sql_map_lambda(query_set),
         self.result_map.result_fields,
         use_ordered_dict=True
     )))
Beispiel #8
0
    def result_field_lookup(self):
        """
            Returns a lookup that maps some field names to a lambda that describes
            how to create a human readable form of the field value. This is used by the FeatureResource
        :return:
        """

        if not self.result_map:
            # If a query has never been stored, we need to sync to an empty query
            self.sync_to_query()

        return compact_dict(
            map_dict_to_dict(self.field_map, self.result_map.field_lookup))
    def create_result_map(self, related_models=[], map_path_segments={}):
        """
            Given the field_paths of the queryset, returns a ResultMap instance.
            ResultMap.result_fields is a list of field_paths minus specifically omitted ones--
            the parent id and geometry column.
            ResultMap.title_lookup is a lookup from the field_path to a title appropriate for the user.
            The generated title uses '.' in place of '__'
            ResultMap.value_map is a lookup from the field_path to a property path that describes
            how to convert the value to a more human readable form. This is used to convert
            instances to a readable label and dates, etc, to a more readable format.
            :param: related_models: pass the related_models represented in the query results so that unneeded
            paraent reference fields can be removed from the result fields
            :param: map_path_segments: An optional dict that matches segments of the field_paths. The value
            corresponding the key is the name to convert it to for the title. If the value is None it will
            be eliminated from the path when it is rejoined with '.'
        """

        result_paths = self.model_result_paths(related_models)
        # Get a mapping of the each result field_path to its field class path along
        # with the related model of that field, if the field is a ForeignKey or AutoField
        result_field_path_lookup = self.model_result_field_path_field_lookup(
            related_models, True)
        join_models = map(lambda model: full_module_path(model.__base__),
                          related_models)
        return ResultMap(
            # Replace '__' with '_x_'. We can't use __ because it confuses tastypie
            result_fields=map(lambda path: string.replace(path, '__', '_x_'),
                              result_paths),
            # Create a lookup from field name to title
            # The only processing we do to the title is to remove the middle path
            title_lookup=map_to_dict(
                lambda path: [
                    # Replace '__' with '_x_'. We can't use __ because it confuses tastypie
                    string.replace(path, '__', '_x_'),
                    # match each segment to map_path_segments or failing that return the segment
                    # remove segments that map to None
                    '__'.join(
                        compact(
                            map(
                                lambda segment: map_path_segments.get(
                                    segment, segment), path.split('__'))))
                ],
                result_paths),
            field_lookup=map_dict_to_dict(
                lambda field_path, tup: [field_path, tup[0]],
                result_field_path_lookup),
            related_model_lookup=compact_dict(
                map_dict_to_dict(lambda field_path, tup: [field_path, tup[1]],
                                 result_field_path_lookup)),
            join_models=join_models,
        )
    def result_field_lookup(self):
        """
            Returns a lookup that maps some field names to a lambda that describes
            how to create a human readable form of the field value. This is used by the FeatureResource
        :return:
        """

        if not self.result_map:
            # If a query has never been stored, we need to sync to an empty query
            self.sync_to_query()

        return compact_dict(map_dict_to_dict(
            self.field_map,
            self.result_map.field_lookup))
Beispiel #11
0
def build_style_string(style, separator=' '):
    """
        Creates key value pairs as a string for the given Style with the given separator
        between the paris
    :param style:
    :param separator: Default ' '
    :return:
    """

    style_string = separator.join(
        map_dict(
            lambda key, value: '{key}: {value};'.format(key=dasherize(key), value=map_value(value)),
            compact_dict(style)))

    return style_string
def build_style_string(style, separator=' '):
    """
        Creates key value pairs as a string for the given Style with the given separator
        between the paris
    :param style:
    :param separator: Default ' '
    :return:
    """

    style_string = separator.join(
        map_dict(
            lambda key, value: '{key}: {value};'.format(key=dasherize(key), value=map_value(value)),
            compact_dict(style)))

    return style_string
Beispiel #13
0
    def create_result_map(self, related_models=[], map_path_segments={}):
        """
            Given the field_paths of the queryset, returns a ResultMap instance.
            ResultMap.result_fields is a list of field_paths minus specifically omitted ones--
            the parent id and geometry column.
            ResultMap.title_lookup is a lookup from the field_path to a title appropriate for the user.
            The generated title uses '.' in place of '__'
            ResultMap.value_map is a lookup from the field_path to a property path that describes
            how to convert the value to a more human readable form. This is used to convert
            instances to a readable label and dates, etc, to a more readable format.
            :param: related_models: pass the related_models represented in the query results so that unneeded
            paraent reference fields can be removed from the result fields
            :param: map_path_segments: An optional dict that matches segments of the field_paths. The value
            corresponding the key is the name to convert it to for the title. If the value is None it will
            be eliminated from the path when it is rejoined with '.'
        """

        result_paths = self.model_result_paths(related_models)
        # Get a mapping of the each result field_path to its field class path along
        # with the related model of that field, if the field is a ForeignKey or AutoField
        result_field_path_lookup = self.model_result_field_path_field_lookup(related_models, True)
        join_models = map(lambda model: full_module_path(model.__base__), related_models)
        return ResultMap(
            # Replace '__' with '_x_'. We can't use __ because it confuses tastypie
            result_fields=map(lambda path: string.replace(path, '__', '_x_'), result_paths),
            # Create a lookup from field name to title
            # The only processing we do to the title is to remove the middle path
            title_lookup=map_to_dict(
                lambda path: [
                    # Replace '__' with '_x_'. We can't use __ because it confuses tastypie
                    string.replace(path, '__', '_x_'),
                    # match each segment to map_path_segments or failing that return the segment
                    # remove segments that map to None
                    '__'.join(compact(
                        map(
                            lambda segment: map_path_segments.get(segment, segment),
                            path.split('__')
                        )
                    ))
                ],
                result_paths
            ),
            field_lookup=map_dict_to_dict(lambda field_path, tup: [field_path, tup[0]], result_field_path_lookup),
            related_model_lookup=compact_dict(map_dict_to_dict(lambda field_path, tup: [field_path, tup[1]], result_field_path_lookup)),
            join_models=join_models,

        )
Beispiel #14
0
    def related_field_lookup(self):
        """
            Only for join queries
            Looks for any field of type AutoField and returns a key value of the related field,
            except for the id field. This is not for related_models being joined, but rather
            for models related to the feature tables, like BuiltForm
            For example built_form_id=AutoField maps to built_form_id=lambda built_form_id:
            :param The JoinFeature class
        :return:
        """
        def related_field_map(field_path, related_model_class_path):
            """
                This helps join feature_classes resolve related models,
                such as BuiltForms. The join feature class can't do this
                through the query since we have to use a values() query.
                Thus the query only contains built_form_id and not built_form with a
                reference to the built_form instance. The API needs to be
                able to return a property built_form=uri so we tell it how do
                do that here.
            :param field_path:
            :param related_model_class_path:
            :return: a key and value, the key is the escaped path (using _x_ for __) with the
             final _id removed and the value is
            the related model class. Ex: built_form_id results in
            [built_form, BuiltForm] for the main model or geographies_[scope_id]_end_state_feature__built_form_id in
            [geographies_[scope_id]_x_end_state_feature_x_built_form, BuiltForm]
            """

            # For static classes you module name resolution. For dynamic classes rely on current truth
            # that dynamic classes are all created in the main app, since module name resolution relies
            # on static module files
            logger.debug("Resolving %s" % related_model_class_path if\
                'dynamic_subclassing' not in related_model_class_path else\
                'main.%s' % related_model_class_path.split('.')[-1])

            related_model_class = resolve_module_attr(related_model_class_path)

            escaped_field_path = field_path.replace(r'_id$',
                                                    '').replace('__', '_x_')
            return [escaped_field_path, related_model_class]

        return compact_dict(
            map_dict_to_dict(related_field_map,
                             self.result_map.related_model_lookup))
    def related_field_lookup(self):
        """
            Only for join queries
            Looks for any field of type AutoField and returns a key value of the related field,
            except for the id field. This is not for related_models being joined, but rather
            for models related to the feature tables, like BuiltForm
            For example built_form_id=AutoField maps to built_form_id=lambda built_form_id:
            :param The JoinFeature class
        :return:
        """
        def related_field_map(field_path, related_model_class_path):
            """
                This helps join feature_classes resolve related models,
                such as BuiltForms. The join feature class can't do this
                through the query since we have to use a values() query.
                Thus the query only contains built_form_id and not built_form with a
                reference to the built_form instance. The API needs to be
                able to return a property built_form=uri so we tell it how do
                do that here.
            :param field_path:
            :param related_model_class_path:
            :return: a key and value, the key is the escaped path (using _x_ for __) with the
             final _id removed and the value is
            the related model class. Ex: built_form_id results in
            [built_form, BuiltForm] for the main model or geographies_[scope_id]_end_state_feature__built_form_id in
            [geographies_[scope_id]_x_end_state_feature_x_built_form, BuiltForm]
            """

            # For static classes you module name resolution. For dynamic classes rely on current truth
            # that dynamic classes are all created in the main app, since module name resolution relies
            # on static module files
            logger.debug("Resolving %s" % related_model_class_path if\
                'dynamic_subclassing' not in related_model_class_path else\
                'main.%s' % related_model_class_path.split('.')[-1])

            related_model_class = resolve_module_attr(related_model_class_path)

            escaped_field_path = field_path.replace(r'_id$', '').replace('__', '_x_')
            return [escaped_field_path, related_model_class]

        return compact_dict(map_dict_to_dict(
            related_field_map,
            self.result_map.related_model_lookup))
Beispiel #16
0
    def test_config_entity_api__permissions(self):
        """
            Make sure that users only get ConfigEntity's that match their permission settings
        :return:
        """

        permission_configuration = TestConfigEntityPermissions.config_entity_configuration(
        )
        resource_name = 'config_entity'

        # Iterate through the test_configurstions and extract a user for each group_key
        # Make a dict with the user as the key and all the instances from the test_config that the
        # user corresponds to. This gives a lookup of a user to the config_entities that we expect
        # the user to be able to view
        # Create a user->instances dict
        # Combine our {user1:instances, user2:instances,...} dicts
        user_to_expected_instances = merge_dict_list_values(
            *map(
                lambda test_configuration:\
                    # Combine our [user, instance] pairs into {user1:instances, user2:instances,...}
                    # Remove null keys (owing to groups with no users)


                    compact_dict(map_to_dict_with_lists(
                        # Each test_configuration has several groups.
                        # For each group resolve a user and return [user, instance]
                        lambda group_key: [
                            get_first_value_or_none(Group.objects.get(name=group_key).user_set.all()),
                            test_configuration['instance']],
                        test_configuration['groups'].keys())),
                permission_configuration.test_configuration)
        )

        all_instances = set(
            unique(flatten(user_to_expected_instances.values())))
        for user, instances in user_to_expected_instances.items():
            other_instances = all_instances - set(instances)
            # Fetch all instances with this user and create a lookup so we can test
            # that the resulting instances are present or not present as expected according to
            # the permissions
            response = self.get(resource_name, user=user)
            result_instance_lookup = map_to_dict(
                lambda instance_dict:
                [int(instance_dict['id']), instance_dict],
                self.deserialize(response)['objects'])

            for instance in instances:
                matching_instance = result_instance_lookup.get(instance.id)
                assert_is_not_none(matching_instance,
                                   "User %s should have view permission to instance %s with id %s and key %s but does." % \
                                   (user.username,
                                    instance,
                                    instance.id,
                                    permission_configuration.key_class.Fab.remove(
                                        permission_configuration.instance_key_lambda(instance))))

            for instance in other_instances:
                assert_is_none(matching_instance,
                                   "User %s should not have view permission to instance %s with id %s and key %s but does." % \
                                   (user.username,
                                    instance,
                                    instance.id,
                                    permission_configuration.key_class.Fab.remove(
                                        permission_configuration.instance_key_lambda(instance))))