Esempio n. 1
0
    def allowed_fields(self, template_id='', permission_type='read'):

        if template_id:

            """
            Collect all of the templates the current user has access to, including both
            explicitly allowed templates and public templates
            """
            explicitly_allowed_templates_ = self.explicitly_allowed_templates(permission_type)
            logger.debug('All Templates user has permission to %s', explicitly_allowed_templates_)

            public_templates_ = self.public_templates()
            logger.debug('All Public Templates %s', public_templates_)

            id_list_ = explicitly_allowed_templates_ + public_templates_
            logger.debug('All Fields user has permission to %s', id_list_)

        else:
            id_list_ = self.explicitly_allowed_fields(permission_type)
            logger.debug('All Fields user has permission to %s', id_list_)

        return id_list_
Esempio n. 2
0
    def field_create(self, request_object, template_id):

        """
        Make sure that we have everything we need to created the
        template successfully, including things like a Name, an associated
        Application, and a Storage mechanism
        """
        if not template_id:
          logger.error('User %d new Field request failed because they didn\'t submit an Template ID with their request', \
              self.current_user.id)
          return status_.status_400('You didn\'t include a Template to add this field to ... or else you\'re not the admin of this Template'), 400

        """
        Make sure that some data was submitted before proceeding
        """
        if not request_object.data:
          logger.error('User %d new Field request failed because they didn\'t submit any `data` with their request', \
              self.current_user.id)
          return status_.status_400('You didn\'t include any `data` with your request.'), 400

        """
        Convert our request object into usable data
        """
        content_ = json.loads(request_object.data)

        """
        Fields are directly tied to Templates and really have no life of their
        own outside of Templates. Because of that we need to instantiate a
        Template object that we can work with
        """
        allowed_fields = self.allowed_fields(template_id)
        if not template_id in allowed_fields:
          logger.warning('User %d with Templates %s tried to access Template %d', \
              self.current_user.id, allowed_fields, template_id)
          return status_.status_401(), 401

        Template_ = Template().query.get(template_id)

        """
        To create a Field you must at least provide a name for your field
        """
        if not content_.get('name', ''):
          logger.error('User %d new Field request failed because they didn\'t submit any `name` in the `data` of their request', \
              self.current_user.id)
          return status_.status_400('You didn\'t include a `name` in the `data` of your request.'), 400

        """
        To create a Field you must at least provide a data_type for your field
        """
        if not content_.get('data_type', ''):
          logger.error('User %d new Field request failed because they didn\'t submit any `data_type` in the `data` of their request', \
              self.current_user.id)
          return status_.status_400('You didn\'t include a `data_type` in the `data` of your request.'), 400
        elif 'relationship' in content_.get('data_type', '') and not content_.get('relationship', ''):
          logger.error('User %d new Field request failed because they didn\'t submit any `data_type` in the `data` of their request', \
              self.current_user.id)
          return status_.status_400('You can\'t create a Relationship field without specifying the `relationship` ... this starts with type_'), 400


        user_defined_label = sanitize.sanitize_string(content_.get('name', ''))

        """
        If someone's creating a relationship the storage string they've specified
        needs to belong to a template that they are allowed to access
        """
        if content_.get('relationship', ''):

          relationship_storage = content_.get('relationship', '')
          storage_check = Template().query.filter_by(storage=relationship_storage).first()

          if not storage_check.id in allowed_fields:
            logger.error('User %d tried to add a Field to a Template %d which they do not own', \
                self.current_user.id, template_id)
            return status_.status_401('The Template `relationship` string you entered either doesn\'t exist or you don\'t have permission to use it'), 401

          """
          Lastly, make sure that an identical relationship doesn't already exist.
          If the type_ and the template type_ already have a relationship it will
          cause bad things to happen when searching via the API
          """
          duplicate_check = self.check_relationship_field_duplicate(Template_.fields, relationship_storage)
          if duplicate_check:
            logger.warning('User %d tried to add a duplicate relationship type', \
                self.current_user.id)
            return status_.status_400('You already defined a relationship with this Template, you cannot create two relationship fields with the same relationship table.'), 400

        new_field = {
          'label': user_defined_label,
          'name': self.generate_machine_name(user_defined_label),
          'help': sanitize.sanitize_string(content_.get('help', '')),
          'data_type': sanitize.sanitize_string(content_.get('data_type', 'text')),
          'relationship': sanitize.sanitize_string(content_.get('relationship', None)),
          'is_public': sanitize.sanitize_boolean(content_.get('is_public', False)),
          'is_visible': sanitize.sanitize_boolean(content_.get('is_visible', False)),
          'is_listed': sanitize.sanitize_boolean(content_.get('is_listed', False)),
          'is_searchable': sanitize.sanitize_boolean(content_.get('is_searchable', True)),
          'is_required': sanitize.sanitize_boolean(content_.get('is_required', False)),
          'weight': sanitize.sanitize_integer(content_.get('created', 1)),
          'status': sanitize.sanitize_boolean(content_.get('status', True)),
          'options': sanitize.sanitize_string(content_.get('options', '')),
          'templates': [Template_]
        }

        logger.debug('Checking Field, %s', new_field)

        field_ = Field(**new_field)

        db.session.add(field_)
        db.session.commit()

        logger.warning('field %s', field_)


        """
        Section 2: Relate the Template with the Field and the User with the Field
        """
        permission = {
          'read': True,
          'write': True,
          'is_admin': True
        }

        self.set_user_field_permissions(field_, permission, self.current_user)

        self.set_template_field_relationship(field_, Template_)


        """
        Section 3: Create the Field in the Template Storage, if the field will
                   hold data. Some fields, like fieldset, are only for visual
                   and aesthetic purposes and do not need added to the Storage
        """
        if not 'fieldset' in field_.data_type:
          field_storage = self.create_storage_field(Template_, field_)

          if 'relationship' in content_.get('data_type', 'text') or 'file' in content_.get('data_type', 'text'):
              field_.association = field_storage['association']
              field_.relationship = field_storage['relationship']
              db.session.commit()

        return field_
Esempio n. 3
0
    def get_storage(self, template, fields=[], is_relationship=False, relationship=True):

        if type(template) is str:
            class_name = str(template)
            relationships = []
        else:
            class_name = str(template.storage)

            """
      Check to see if we need to load the full model or a slim model.

      A full model includes all relationships, a slim model only includes
      first level field and excludes all attachments and relationships.
      """
            if relationship:
                relationships = self.get_relationship_fields(template.fields)
            else:
                relationships = []

        logger.debug("Dynamic Model executed for %s", class_name)

        arguments = {"class_name": class_name, "relationships": relationships}

        class_arguments = self.get_class_arguments(**arguments)

        Model = type(class_name, (db.Model,), class_arguments)

        """
    For the API to return items properly, we should check to see if the fields
    we are attempting to call are marked as listed or not.
    """
        if fields or hasattr(template, "fields"):

            if is_relationship:
                public_fields = [
                    "id",
                    "name",
                    "created",
                    "updated",
                    "status",
                    "filename",
                    "filepath",
                    "caption",
                    "credit",
                    "credit_link",
                ]
            else:
                public_fields = [
                    "id",
                    "name",
                    "created",
                    "updated",
                    "geometry",
                    "status",
                    "filename",
                    "filepath",
                    "caption",
                    "credit",
                    "credit_link",
                ]

            for field in fields:
                if field.is_listed and field.data_type == "relationship":
                    public_fields.append(field.relationship)
                elif field.is_listed and field.data_type == "file":
                    public_fields.append(field.relationship)
                elif field.is_listed:
                    public_fields.append(field.name)

            # Remove all duplicate names before passing along to public fields
            # self.__public__ = list(set(public_fields))
            self.__public__["default"] = public_fields

        return Model
Esempio n. 4
0
    def get_class_arguments(self, class_name, relationships):

        """
    Start an empty object to store all of our Class Arguments
    """
        class_arguments = {}

        """
    Automatically load all of our basic table fields and other
    meta information
    """
        class_arguments["__table__"] = db.Table(class_name, db.metadata, autoload=True, autoload_with=db.engine)
        class_arguments["__tablename__"] = class_name
        class_arguments["__table_args__"] = {"extend_existing": True}

        """
    Unfortunately we have to manually load the relationships that
    our models need to work properly.

    To build relationships out properly we need a few things:

    'type_5740f6daa55f4fc790e7eeacb96d726e' : db.relationship('type_5740f6daa55f4fc790e7eeacb96d726e', secondary=our_reference_table, backref=db.backref(class_name))

    1. We need the name of the association table (e.g., ref_XXXXXXXXXXXXXXXXXXXXX)
    2. We need the name of the other table that actually contains the content to
       be referenced (e.g., type_XXXXXXXXXXXXXXXXXXX)
    3. We should have a model class for the association table
    4. We need the name of the class or 'storage' of the Class being acted on

    """
        relationship_message = "No relationships"

        if relationships:
            relationship_message = "Relationships found"
            for relationship in relationships:

                logger.debug("Adding relationship %s (%s) to model", relationship.name, relationship.relationship)

                table_name = str(relationship.relationship)

                RelationshipModel = self.get_storage(table_name, is_relationship=True)

                """
        Setup our association table for each relationship that we have
        in our fields list
        """
                parent_id_key = str(class_name) + ".id"
                child_id_key = table_name + ".id"

                association_table = db.Table(
                    str(relationship.association),
                    db.metadata,
                    db.Column("parent_id", db.Integer, db.ForeignKey(parent_id_key), primary_key=True),
                    db.Column("child_id", db.Integer, db.ForeignKey(child_id_key), primary_key=True),
                    extend_existing=True,
                    autoload=True,
                    autoload_with=db.engine,
                )

                class_arguments[table_name] = db.relationship(
                    RelationshipModel, secondary=association_table, cascade="", backref=class_name
                )

        logger.debug("Relationships > %s", relationship_message)

        return class_arguments
Esempio n. 5
0
  def allowed_templates(self, application_id='', permission_type='read'):

    if application_id:

      """
      Before doing anything make sure the user is allowed to access the
      application in the first place.
      """
      allowed_applications = self.allowed_applications('read')

      if not application_id in allowed_applications:
        logger.warning('User %d with Applications %s tried to access Application %d', \
            self.current_user.id, allowed_applications, application_id)
        return status_.status_401('You need to be logged in to access applications'), 401

      """
      Collect all of the templates the current user has access to, including both
      explicitly allowed templates and public templates
      """
      explicitly_allowed_templates_ = self.explicitly_allowed_templates(permission_type)
      logger.debug('All Templates user has permission to %s', explicitly_allowed_templates_)

      public_templates_ = self.public_templates()
      logger.debug('All Public Templates %s', public_templates_)

      combined_access = explicitly_allowed_templates_ + public_templates_

      """
      All Templates belonging to the requested Application
      """
      application_templates_ = self.applications_templates(application_id)
      logger.debug('All Templates for this Application %s', application_templates_)

      """
      Using the `combined_template_access` filter the Application Templates (the
      Templates only for this Application that the user has access to)
      """
      template_id_list_ = set(combined_access) & set(application_templates_)
      logger.debug('Templates to display %s', template_id_list_)

    else:

      """
      Collect all of the templates the current user has access to, including both
      explicitly allowed templates and public templates
      """
      explicitly_allowed_templates_ = self.explicitly_allowed_templates(permission_type)
      logger.debug('All Templates user has permission to %s', explicitly_allowed_templates_)

      public_templates_ = self.public_templates()
      logger.debug('All Public Templates %s', public_templates_)

      template_id_list_ = explicitly_allowed_templates_ + public_templates_


    return template_id_list_