示例#1
0
 def _extra_table_args(klass):
     # pylint: disable=unused-argument
     return (
         db.UniqueConstraint('workflow_id', 'person_id'),
         db.Index('ix_workflow_id', 'workflow_id'),
         db.Index('ix_person_id', 'person_id'),
     )
示例#2
0
 def _extra_table_args(model):
     return (
         db.Index('fk_{}_contact'.format(model.__tablename__),
                  'contact_id'),
         db.Index('fk_{}_secondary_contact'.format(model.__tablename__),
                  'secondary_contact_id'),
     )
示例#3
0
 def _extra_table_args(_):
     return (
         db.Index('ix_controls_principal_assessor',
                  'principal_assessor_id'),
         db.Index('ix_controls_secondary_assessor',
                  'secondary_assessor_id'),
     )
示例#4
0
 def __table_args__(cls):  # pylint: disable=no-self-argument
   return (
       db.Index('ix_{}_tags'.format(cls.__tablename__), 'tags'),
       db.Index('ix_{}_key'.format(cls.__tablename__), 'key'),
       db.Index('ix_{}_type'.format(cls.__tablename__), 'type'),
       db.Index('ix_{}_context_id'.format(cls.__tablename__), 'context_id'),
   )
示例#5
0
 def _extra_table_args(_):
     return (
         db.UniqueConstraint("parent_type", "parent_id", "child_type",
                             "child_id"),
         db.Index("ix_snapshots_parent", "parent_type", "parent_id"),
         db.Index("ix_snapshots_child", "child_type", "child_id"),
     )
示例#6
0
 def __table_args__(self):
     return (
         db.Index('ix_{}_tags'.format(self.__tablename__), 'tags'),
         db.Index('ix_{}_key'.format(self.__tablename__), 'key'),
         db.Index('ix_{}_type'.format(self.__tablename__), 'type'),
         db.Index('ix_{}_context_id'.format(self.__tablename__),
                  'context_id'),
     )
示例#7
0
 def _extra_table_args(class_):
     return (
         db.Index('events_modified_by', 'modified_by_id'),
         db.Index(
             'ix_{}_updated_at'.format(class_.__tablename__),
             'updated_at',
         ),
     )
示例#8
0
 def _extra_table_args(_):
   return (
       db.Index("revisions_modified_by", "modified_by_id"),
       db.Index("fk_revisions_resource", "resource_type", "resource_id"),
       db.Index("fk_revisions_source", "source_type", "source_id"),
       db.Index("fk_revisions_destination",
                "destination_type", "destination_id"),
   )
示例#9
0
 def _extra_table_args(cls):
     return (
         db.UniqueConstraint('source_id', 'source_type', 'destination_id',
                             'destination_type'),
         db.Index('ix_relationships_source', 'source_type', 'source_id'),
         db.Index('ix_relationships_destination', 'destination_type',
                  'destination_id'),
     )
示例#10
0
 def __table_args__(cls):  # pylint: disable=no-self-argument
     return (
         db.Index("ix_source", "source_type", "source_id", "source_attr"),
         # db.Index("value_string"), not needed yet
         db.Index("ix_value_integer", "value_integer"),
         db.Index("ix_value_datetime", "value_datetime"),
         db.UniqueConstraint(
             "object_id",
             "object_type",
             "attribute_definition_id",
             "attribute_template_id",
             name="uq_attributes",
         ),
     )
示例#11
0
 def __table_args__(self):
   return (
       # NOTE
       # This is here to prevent Alembic from wanting to drop the index, but
       # the DDL below or a similar Alembic migration should be used to create
       # the index.
       db.Index('{}_text_idx'.format(self.__tablename__), 'content'),
       # These are real indexes
       db.Index('ix_{}_key'.format(self.__tablename__), 'key'),
       db.Index('ix_{}_type'.format(self.__tablename__), 'type'),
       db.Index('ix_{}_tags'.format(self.__tablename__), 'tags'),
       db.Index('ix_{}_context_id'.format(self.__tablename__), 'context_id'),
       # Only MyISAM supports fulltext indexes until newer MySQL/MariaDB
       {'mysql_engine': 'myisam'},
   )
示例#12
0
 def _extra_table_args(_):
   return (
       db.UniqueConstraint(
           'person_id', 'ac_role_id', 'object_id', 'object_type'
       ),
       db.Index('idx_object_type_object_idx', 'object_type', 'object_id'),
   )
示例#13
0
 def _extra_table_args(cls):
   return (
       db.UniqueConstraint('document_id',
                           'documentable_id',
                           'documentable_type'),
       db.Index('ix_document_id', 'document_id'),
   )
示例#14
0
文件: list.py 项目: pypros/ggrc-core
 def _extra_table_args(_):
   return (
       db.UniqueConstraint(
           'ac_role_id',
           'object_id',
           'object_type',
           'parent_id_nn',
       ),
       db.Index('idx_object_type_object_idx', 'object_type', 'object_id'),
       db.Index('ix_role_object', 'ac_role_id', 'object_type', 'object_id'),
       db.Index(
           'idx_object_type_object_id_parent_id_nn',
           'object_type',
           'object_id',
           'parent_id_nn',
       ),
   )
示例#15
0
 def _extra_table_args(cls):
     return (db.Index('ix_{}_meta_kind'.format(cls.__tablename__),
                      'meta_kind'), )
示例#16
0
 def _extra_table_args(cls):
     return (
         db.UniqueConstraint('person_id', 'personable_id',
                             'personable_type'),
         db.Index('ix_person_id', 'person_id'),
     )
示例#17
0
 def _extra_table_args(_):
     return (
         db.Index('ix_people_name_email', 'name', 'email'),
         db.Index('uq_people_email', 'email', unique=True),
     )
示例#18
0
 def _extra_table_args(_):
     return (db.Index('ix_context_related_object', 'related_object_type',
                      'related_object_id'), )
示例#19
0
 def _extra_table_args(cls):
     return (db.Index('ix_{}_is_biz_process'.format(cls.__tablename__),
                      'is_biz_process'), )
示例#20
0
 def _extra_table_args(cls):
     return (db.Index('ix_folderable_id_type', 'folderable_id',
                      'folderable_type'), )
示例#21
0
 def _extra_table_args(_):
     return (db.Index("fk_instance", "instance_id", "instance_type"),
             db.Index("ix_decline_datetime", "decline_datetime"),
             db.Index("ix_apply_datetime", "apply_datetime"),
             db.Index("ix_proposed_notified_datetime",
                      "proposed_notified_datetime"))
示例#22
0
 def _extra_table_args(cls):
   return (
       db.Index('ix_options_role', 'role'),
   )
示例#23
0
 def _extra_table_args(cls):
     return (
         db.UniqueConstraint('person_id', 'ownable_id', 'ownable_type'),
         db.Index('ix_object_owners_ownable', 'ownable_type', 'ownable_id'),
     )
示例#24
0
 def _extra_table_args(cls):
     return (db.Index('ix_{}_updated_at'.format(cls.__tablename__),
                      'updated_at'), )
示例#25
0
 def _extra_table_args(cls):
     return (
         db.UniqueConstraint('audit_id', 'auditable_id', 'auditable_type'),
         db.Index('ix_audit_id', 'audit_id'),
     )
示例#26
0
 def _extra_table_args(klass):
     # pylint: disable=unused-argument
     return (
         db.UniqueConstraint('task_group_id', 'object_id', 'object_type'),
         db.Index('ix_task_group_id', 'task_group_id'),
     )
示例#27
0
 def _extra_table_args(class_):
     return (db.Index('events_modified_by', 'modified_by_id'), )
示例#28
0
 def _extra_table_args(model):
   """Apply extra table args (like indexes) to model definition."""
   return (
       db.Index('ix_{}_updated_at'.format(model.__tablename__), 'updated_at'),
   )
示例#29
0
class CustomAttributeDefinition(attributevalidator.AttributeValidator,
                                base.ContextRBAC, mixins.Base, mixins.Titled,
                                db.Model):
    """Custom attribute definition model.

  Attributes:
    multi_choice_mandatory: comma separated values of mandatory bitmaps.
      First lsb is for comment, second bit is for attachement.
  """

    __tablename__ = 'custom_attribute_definitions'

    definition_type = db.Column(db.String, nullable=False)
    definition_id = db.Column(db.Integer)
    attribute_type = db.Column(db.String, nullable=False)
    multi_choice_options = db.Column(db.String)
    multi_choice_mandatory = db.Column(db.String)
    mandatory = db.Column(db.Boolean)
    helptext = db.Column(db.String)
    placeholder = db.Column(db.String)

    attribute_values = db.relationship('CustomAttributeValue',
                                       backref='custom_attribute',
                                       cascade='all, delete-orphan')

    @property
    def definition_attr(self):
        return '{0}_definition'.format(self.definition_type)

    @property
    def definition(self):
        return getattr(self, self.definition_attr)

    @property
    def value_mapping(self):
        return self.ValidTypes.DEFAULT_VALUE_MAPPING.get(
            self.attribute_type) or {}

    @classmethod
    def get_default_value_for(cls, attribute_type):
        return cls.ValidTypes.DEFAULT_VALUE.get(attribute_type)

    @builder.simple_property
    def default_value(self):
        return self.get_default_value_for(self.attribute_type)

    def get_indexed_value(self, value):
        return self.value_mapping.get(value, value)

    @definition.setter
    def definition(self, value):
        self.definition_id = getattr(value, 'id', None)
        if hasattr(value, '_inflector'):
            self.definition_type = value._inflector.table_singular
        else:
            self.definition_type = ''
        return setattr(self, self.definition_attr, value)

    _extra_table_args = (UniqueConstraint('definition_type',
                                          'definition_id',
                                          'title',
                                          name='uq_custom_attribute'),
                         db.Index('ix_custom_attributes_title', 'title'))

    _include_links = [
        'definition_type',
        'definition_id',
        'attribute_type',
        'multi_choice_options',
        'multi_choice_mandatory',
        'mandatory',
        'helptext',
        'placeholder',
    ]

    _api_attrs = reflection.ApiAttributes(
        reflection.Attribute("default_value",
                             read=True,
                             create=False,
                             update=False), *_include_links)

    _sanitize_html = [
        "multi_choice_options",
        "helptext",
        "placeholder",
    ]

    _reserved_names = {}

    def _clone(self, target):
        """Clone custom attribute definitions."""
        data = {
            "title": self.title,
            "definition_type": self.definition_type,
            "definition_id": target.id,
            "context": target.context,
            "attribute_type": self.attribute_type,
            "multi_choice_options": self.multi_choice_options,
            "multi_choice_mandatory": self.multi_choice_mandatory,
            "mandatory": self.mandatory,
            "helptext": self.helptext,
            "placeholder": self.placeholder,
        }
        ca_definition = CustomAttributeDefinition(**data)
        db.session.add(ca_definition)
        return ca_definition

    class ValidTypes(object):
        """Class representing valid custom attribute definitions.

    Basically an enum, therefore no need for public methods.
    """
        # pylint: disable=too-few-public-methods
        TEXT = "Text"
        RICH_TEXT = "Rich Text"
        DROPDOWN = "Dropdown"
        CHECKBOX = "Checkbox"
        DATE = "Date"
        MAP = "Map"

        DEFAULT_VALUE = {
            CHECKBOX: "0",
            RICH_TEXT: "",
            TEXT: "",
            DROPDOWN: "",
            DATE: ""
        }

        DEFAULT_VALUE_MAPPING = {
            CHECKBOX: {
                True: "Yes",
                False: "No",
                "0": "No",
                "1": "Yes",
            },
        }

    class MultiChoiceMandatoryFlags(object):
        """Enum representing flags in multi_choice_mandatory bitmaps."""
        # pylint: disable=too-few-public-methods
        COMMENT_REQUIRED = 0b001
        EVIDENCE_REQUIRED = 0b010
        URL_REQUIRED = 0b100

    VALID_TYPES = {
        "Text": "Text",
        "Rich Text": "Rich Text",
        "Dropdown": "Dropdown",
        "Checkbox": "Checkbox",
        "Date": "Date",
        "Person": "Map:Person",
    }

    @validates("attribute_type")
    def validate_attribute_type(self, _, value):
        """Check that provided attribute_type is allowed."""
        if value not in self.VALID_TYPES.values():
            raise ValidationError("Invalid attribute_type: got {v}, "
                                  "expected one of {l}".format(
                                      v=value,
                                      l=list(self.VALID_TYPES.values())))
        return value

    @validates("multi_choice_options")
    def validate_multi_choice_options(self, _, value):
        """Strip spaces around options in dropdown options."""
        # pylint: disable=no-self-use
        # TODO: this should be "if value is not None" to disallow value == ""
        if value:
            value_list = [part.strip() for part in value.split(",")]
            value_set = set(value_list)
            if len(value_set) != len(value_list):
                raise ValidationError(
                    "Duplicate dropdown options are not allowed: "
                    "'{}'".format(value))
            if "" in value_set:
                raise ValidationError(
                    "Empty dropdown options are not allowed: '{}'".format(
                        value))
            value = ",".join(value_list)

        return value

    @validates("multi_choice_mandatory")
    def validate_multi_choice_mandatory(self, _, value):
        """Strip spaces around bitmas in dropdown options."""
        # pylint: disable=no-self-use
        if value:
            value = ",".join(part.strip() for part in value.split(","))

        return value

    def validate_assessment_title(self, name):
        """Check assessment title uniqueness.

    Assessment CAD should not match any name from assessment_template.
    Currently assessment templates do not have global custom attributes, but
    in the future global CAD on assessment templates could be applied to all
    generated assessments. That's why we do not differentiate between global
    and local CAD here.

    Args:
      name: Assessment custom attribute definition title.
    Raises:
      ValueError if name is an invalid CAD title.
    """
        if self.definition_id:
            # Local Assessment CAD can match local and global Assessment Template
            # CAD.
            # NOTE: This is not the best way of checking if the current CAD is local,
            # since it relies on the fact that if definition_id will be set, it will
            # be set along with definition_type. If we manually set definition_type
            # then title then definition_id, this check would fail.
            return

        if not getattr(flask.g, "template_cad_names", set()):
            query = db.session.query(self.__class__.title).filter(
                self.__class__.definition_type == "assessment_template")
            flask.g.template_cad_names = {cad.title.lower() for cad in query}

        if name in flask.g.template_cad_names:
            raise ValueError(
                u"Local custom attribute '{}' "
                u"already exists for this object type.".format(name))

    @validates("title", "definition_type")
    def validate_title(self, key, value):
        """Validate CAD title/name uniqueness.

    Note: title field is used for storing CAD names.
    CAD names need to follow 4 uniqueness rules:
      1) Names must not match any attribute name on any existing object.
      2) Object level CAD names must not match any global CAD name.
      3) Object level CAD names can clash, but not for the same Object
         instance. This means we can have two CAD with a name "my cad", with
         different attributable_id fields.
      4) Names must not match any existing custom attribute role name

    Third rule is handled by the database with unique key uq_custom_attribute
    (`definition_type`,`definition_id`,`title`).

    This validator should check for name collisions for 1st and 2nd rule.

    This validator works, because definition_type is never changed. It only
    gets set when the cad is created and after that only title filed can
    change. This makes validation using both fields possible.

    Args:
      value: custom attribute definition name

    Returns:
      value if the name passes all uniqueness checks.
    """

        if key == "title" and self.definition_type:
            name = value.lower()
            definition_type = self.definition_type
        elif key == "definition_type" and self.title:
            name = self.title.lower()
            definition_type = value.lower()
        else:
            return value

        if name in self._get_reserved_names(definition_type):
            raise ReservedNameError(
                u"Attribute '{}' is reserved for this object type.".format(
                    name))

        if (self._get_global_cad_names(definition_type).get(name) is not None
                and self._get_global_cad_names(definition_type).get(name) !=
                self.id):
            raise ValueError(
                u"Global custom attribute '{}' "
                u"already exists for this object type".format(name))
        model_name = get_inflector_model_name_dict()[definition_type]
        acrs = {
            i.lower()
            for i in acr.get_custom_roles_for(model_name).values()
        }
        if name in acrs:
            raise ValueError(
                u"Custom Role with a name of '{}' "
                u"already exists for this object type".format(name))

        if definition_type == "assessment":
            self.validate_assessment_title(name)

        return value

    def log_json(self):
        """Add extra fields to be logged in CADs."""
        results = super(CustomAttributeDefinition, self).log_json()
        results["default_value"] = self.default_value
        return results
示例#30
0
 def _extra_table_args(model):
   return (
       db.Index('fk_{}_contexts'.format(model.__tablename__), 'context_id'),
   )