示例#1
0
class WithLastAssessmentDate(attributable.Attributable):
    """Defines logic to get max finished_date of all Asmts over own Snapshots."""
    # pylint: disable=too-few-public-methods

    _api_attrs = reflection.ApiAttributes(
        reflection.Attribute("last_assessment_date",
                             create=False,
                             update=False), )

    _aliases = {
        "last_assessment_date": {
            "display_name": "Last Assessment Date",
            "view_only": True,
        },
    }

    _fulltext_attrs = [
        attributes.DatetimeFullTextAttr("last_assessment_date",
                                        "last_assessment_date")
    ]

    @simple_property
    def last_assessment_date(self):
        lad_attr = self.attributes.get("last_assessment_date")
        return lad_attr.value_datetime if lad_attr else None
示例#2
0
class VerifiedDate(object):
    """Adds 'Verified Date' which is set when status is set to 'Verified'.

  When object is verified the status is overridden to 'Final' and the
  information about verification exposed as the 'verified' boolean.
  Requires Stateful to be mixed in as well.
  """

    VERIFIED_STATES = {u"Verified"}
    DONE_STATES = {}

    # pylint: disable=method-hidden
    # because validator only sets date per model instance
    @declared_attr
    def verified_date(cls):  # pylint: disable=no-self-argument
        return deferred(db.Column(db.DateTime, nullable=True), cls.__name__)

    @hybrid_property
    def verified(self):
        return self.verified_date != None  # noqa

    _api_attrs = reflection.ApiAttributes(
        reflection.Attribute('verified', create=False, update=False),
        reflection.Attribute('verified_date', create=False, update=False),
    )

    _aliases = {
        "verified_date": {
            "display_name": "Verified Date",
            "description": "Automatically provided values",
        }
    }

    _fulltext_attrs = [
        attributes.DatetimeFullTextAttr("verified_date", "verified_date"),
        "verified",
    ]

    @classmethod
    def indexed_query(cls):
        return super(VerifiedDate, cls).indexed_query().options(
            orm.Load(cls).load_only("verified_date"), )

    @validates('status')
    def validate_status(self, key, value):
        """Update verified_date on status change, make verified status final."""
        # Sqlalchemy only uses one validator per status (not necessarily the
        # first) and ignores others. This enables cooperation between validators
        # since 'status' is not defined here.
        if hasattr(super(VerifiedDate, self), "validate_status"):
            value = super(VerifiedDate, self).validate_status(key, value)
        if (value in self.VERIFIED_STATES
                and self.status not in self.VERIFIED_STATES):
            self.verified_date = datetime.datetime.utcnow()
            value = self.FINAL_STATE
        elif (value not in self.END_STATES
              and (self.status in self.VERIFIED_STATES
                   or self.status in self.DONE_STATES)):
            self.verified_date = None
        return value
示例#3
0
class FinishedDate(object):
  """Adds 'Finished Date' which is set when status is set to a finished state.

  Requires Stateful to be mixed in as well.
  """

  NOT_DONE_STATES = None
  DONE_STATES = {}

  # pylint: disable=method-hidden
  # because validator only sets date per model instance
  @declared_attr
  def finished_date(cls):  # pylint: disable=no-self-argument
    return deferred(
        db.Column(db.DateTime, nullable=True),
        cls.__name__
    )

  _api_attrs = reflection.ApiAttributes(
      reflection.Attribute('finished_date', create=False, update=False),
  )

  _aliases = {
      "finished_date": "Finished Date"
  }

  _fulltext_attrs = [
      attributes.DatetimeFullTextAttr('finished_date', 'finished_date'),
  ]

  @validates('status')
  def validate_status(self, key, value):
    """Update finished_date given the right status change."""
    # Sqlalchemy only uses one validator per status (not necessarily the
    # first) and ignores others. This enables cooperation between validators
    # since 'status' is not defined here.
    if hasattr(super(FinishedDate, self), "validate_status"):
      value = super(FinishedDate, self).validate_status(key, value)
    # pylint: disable=unsupported-membership-test
    # short circuit
    if (value in self.DONE_STATES and
        (self.NOT_DONE_STATES is None or
         self.status in self.NOT_DONE_STATES)):
      self.finished_date = datetime.datetime.now()
    elif ((self.NOT_DONE_STATES is None or
           value in self.NOT_DONE_STATES) and
            self.status in self.DONE_STATES):
      self.finished_date = None
    return value

  @classmethod
  def indexed_query(cls):
    return super(FinishedDate, cls).indexed_query().options(
        orm.Load(cls).load_only("finished_date"),
    )
示例#4
0
class VerifiedDate(object):
    """Adds 'Verified Date' which is set when status is set to 'Verified'.

  When object is verified the status is overridden to 'Final' and the
  information about verification exposed as the 'verified' boolean.
  Requires Stateful to be mixed in as well.
  """

    VERIFIED_STATES = {u"Verified"}
    DONE_STATES = {}

    # pylint: disable=method-hidden
    # because validator only sets date per model instance
    @declared_attr
    def verified_date(cls):
        return deferred(db.Column(db.DateTime, nullable=True), cls.__name__)

    @hybrid_property
    def verified(self):
        return self.verified_date != None  # noqa

    _publish_attrs = [
        reflection.PublishOnly('verified'),
        reflection.PublishOnly('verified_date'),
    ]

    _aliases = {"verified_date": "Verified Date"}

    _fulltext_attrs = [
        attributes.DatetimeFullTextAttr("verified_date", "verified_date"),
        "verified",
    ]

    @validates('status')
    def validate_status(self, key, value):
        """Update verified_date on status change, make verified status final."""
        # Sqlalchemy only uses one validator per status (not necessarily the
        # first) and ignores others. This enables cooperation between validators
        # since 'status' is not defined here.
        if hasattr(super(VerifiedDate, self), "validate_status"):
            value = super(VerifiedDate, self).validate_status(key, value)
        if (value in self.VERIFIED_STATES
                and self.status not in self.VERIFIED_STATES):
            self.verified_date = datetime.datetime.now()
            value = self.FINAL_STATE
        elif (value not in self.VERIFIED_STATES
              and value not in self.DONE_STATES
              and (self.status in self.VERIFIED_STATES
                   or self.status in self.DONE_STATES)):
            self.verified_date = None
        return value
示例#5
0
class CreationTimeTracked(object):
  """
    Mixing for created_at column support.

    `created_at` column will keep track of db record
    creation time.
  """

  @declared_attr
  def created_at(self):
    """
        Date of creation. Set to current time on object creation.
    """
    column = db.Column(
        db.DateTime,
        nullable=False,
        default=lambda: datetime.utcnow().replace(microsecond=0).isoformat(),
    )

    return column

  _api_attrs = reflection.ApiAttributes(
      reflection.Attribute('created_at', create=False, update=False),
  )

  _fulltext_attrs = [
      attributes.DatetimeFullTextAttr('created_at', 'created_at'),
  ]

  _filterable_attrs = [
      "created_at",
  ]

  _aliases = {
      "created_at": {
          "display_name": "Created Date",
          "mandatory": False,
          "description": "Automatically provided values"
      },
  }

  @classmethod
  def indexed_query(cls):
    return super(CreationTimeTracked, cls).indexed_query().options(
        orm.Load(cls).load_only("created_at"),
    )
示例#6
0
class ChangeTracked(object):

  """A model with fields to tracked the last user to modify the model, the
  creation time of the model, and the last time the model was updated.
  """
  @declared_attr
  def modified_by_id(cls):  # pylint: disable=no-self-argument
    """Id of user who did the last modification of the object."""
    return db.Column(db.Integer)

  @declared_attr
  def created_at(cls):  # pylint: disable=no-self-argument
    """Date of creation. Set to current time on object creation."""
    column = db.Column(
        db.DateTime,
        nullable=False,
        default=db.text('current_timestamp'),
    )
    return column

  @declared_attr
  def updated_at(cls):  # pylint: disable=no-self-argument
    """Date of last update. Set to current time on object creation/update."""
    column = db.Column(
        db.DateTime,
        nullable=False,
        default=db.text('current_timestamp'),
        onupdate=db.text('current_timestamp'),
    )
    return column

  @declared_attr
  def modified_by(cls):  # pylint: disable=no-self-argument
    """Relationship to user referenced by modified_by_id."""
    return db.relationship(
        'Person',
        primaryjoin='{0}.modified_by_id == Person.id'.format(cls.__name__),
        foreign_keys='{0}.modified_by_id'.format(cls.__name__),
        uselist=False,
    )

  @staticmethod
  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'),
    )

  # TODO Add a transaction id, this will be handy for generating etags
  # and for tracking the changes made to several resources together.
  # transaction_id = db.Column(db.Integer)

  # REST properties
  _api_attrs = reflection.ApiAttributes(
      reflection.Attribute('modified_by', create=False, update=False),
      reflection.Attribute('created_at', create=False, update=False),
      reflection.Attribute('updated_at', create=False, update=False),
  )
  _fulltext_attrs = [
      attributes.DatetimeFullTextAttr('created_at', 'created_at'),
      attributes.DatetimeFullTextAttr('updated_at', 'updated_at'),
      attributes.FullTextAttr(
          "modified_by", "modified_by", ["email", "name"]
      ),
  ]

  _aliases = {
      "updated_at": "Last Updated",
      "created_at": "Created Date",
      "modified_by": "Last Updated By",
  }

  @classmethod
  def indexed_query(cls):
    return super(ChangeTracked, cls).indexed_query().options(
        orm.Load(cls).load_only("created_at", "updated_at"),
        orm.Load(cls).joinedload(
            "modified_by"
        ).load_only(
            "name", "email", "id"
        ),
    )
示例#7
0
class ChangeTracked(object):
    """A model with fields to tracked the last user to modify the model, the
  creation time of the model, and the last time the model was updated.
  """
    @declared_attr
    def modified_by_id(cls):
        """Id of user who did the last modification of the object."""
        return deferred(db.Column(db.Integer), cls.__name__)

    @declared_attr
    def created_at(cls):
        """Date of creation. Set to current time on object creation."""
        column = db.Column(
            db.DateTime,
            nullable=False,
            default=db.text('current_timestamp'),
        )
        return deferred(column, cls.__name__)

    @declared_attr
    def updated_at(cls):
        """Date of last update. Set to current time on object creation/update."""
        column = db.Column(
            db.DateTime,
            nullable=False,
            default=db.text('current_timestamp'),
            onupdate=db.text('current_timestamp'),
        )
        return deferred(column, cls.__name__)

    @declared_attr
    def modified_by(cls):
        """Relationship to user referenced by modified_by_id."""
        return db.relationship(
            'Person',
            primaryjoin='{0}.modified_by_id == Person.id'.format(cls.__name__),
            foreign_keys='{0}.modified_by_id'.format(cls.__name__),
            uselist=False,
        )

    @staticmethod
    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'), )

    # TODO Add a transaction id, this will be handy for generating etags
    # and for tracking the changes made to several resources together.
    # transaction_id = db.Column(db.Integer)

    # REST properties
    _publish_attrs = [
        'modified_by',
        'created_at',
        'updated_at',
    ]
    _fulltext_attrs = [
        attributes.DatetimeFullTextAttr('created_at', 'created_at'),
        attributes.DatetimeFullTextAttr('updated_at', 'updated_at'),
        attributes.FullTextAttr("modified_by", "modified_by",
                                ["name", "email"]),
    ]

    _update_attrs = []
    _aliases = {
        "updated_at": {
            "display_name": "Last Updated",
            "filter_only": True,
        },
        "created_at": {
            "display_name": "Created Date",
            "filter_only": True,
        },
    }
示例#8
0
class Risk(synchronizable.Synchronizable,
           synchronizable.RoleableSynchronizable,
           mixins.ExternalCustomAttributable, Relatable, PublicDocumentable,
           comment.ExternalCommentable, mixins.TestPlanned,
           mixins.LastDeprecatedTimeboxed, mixins.base.ContextRBAC,
           mixins.BusinessObject, mixins.Folderable, Indexed, db.Model):
    """Basic Risk model."""
    __tablename__ = 'risks'

    # GGRCQ attributes
    external_id = db.Column(db.Integer, nullable=False)
    due_date = db.Column(db.Date, nullable=True)
    created_by_id = db.Column(db.Integer, nullable=False)
    review_status = deferred(db.Column(db.String, nullable=True), "Risk")
    review_status_display_name = deferred(db.Column(db.String, nullable=True),
                                          "Risk")

    # pylint: disable=no-self-argument
    @declared_attr
    def created_by(cls):
        """Relationship to user referenced by created_by_id."""
        return utils.person_relationship(cls.__name__, "created_by_id")

    last_submitted_at = db.Column(db.DateTime, nullable=True)
    last_submitted_by_id = db.Column(db.Integer, nullable=True)

    @declared_attr
    def last_submitted_by(cls):
        """Relationship to user referenced by last_submitted_by_id."""
        return utils.person_relationship(cls.__name__, "last_submitted_by_id")

    last_verified_at = db.Column(db.DateTime, nullable=True)
    last_verified_by_id = db.Column(db.Integer, nullable=True)

    @declared_attr
    def last_verified_by(cls):
        """Relationship to user referenced by last_verified_by_id."""
        return utils.person_relationship(cls.__name__, "last_verified_by_id")

    # Overriding mixin to make mandatory
    @declared_attr
    def description(cls):
        #  pylint: disable=no-self-argument
        return deferred(db.Column(db.Text, nullable=False, default=u""),
                        cls.__name__)

    risk_type = db.Column(db.Text, nullable=True)
    threat_source = db.Column(db.Text, nullable=True)
    threat_event = db.Column(db.Text, nullable=True)
    vulnerability = db.Column(db.Text, nullable=True)

    @validates('review_status')
    def validate_review_status(self, _, value):
        """Add explicit non-nullable validation."""
        # pylint: disable=no-self-use

        if value is None:
            raise exceptions.ValidationError(
                "Review status for the object is not specified")

        return value

    @validates('review_status_display_name')
    def validate_review_status_display_name(self, _, value):
        """Add explicit non-nullable validation."""
        # pylint: disable=no-self-use
        # pylint: disable=invalid-name

        if value is None:
            raise exceptions.ValidationError(
                "Review status display for the object is not specified")

        return value

    _sanitize_html = [
        'risk_type', 'threat_source', 'threat_event', 'vulnerability'
    ]

    _fulltext_attrs = [
        'risk_type', 'threat_source', 'threat_event', 'vulnerability',
        'review_status_display_name',
        attributes.DateFullTextAttr('due_date', 'due_date'),
        attributes.DatetimeFullTextAttr('last_submitted_at',
                                        'last_submitted_at'),
        attributes.DatetimeFullTextAttr('last_verified_at',
                                        'last_verified_at'),
        attributes.FullTextAttr("created_by", "created_by", ["email", "name"]),
        attributes.FullTextAttr("last_submitted_by", "last_submitted_by",
                                ["email", "name"]),
        attributes.FullTextAttr("last_verified_by", "last_verified_by",
                                ["email", "name"])
    ]

    _custom_publish = {
        'created_by': ggrc_utils.created_by_stub,
        'last_submitted_by': ggrc_utils.last_submitted_by_stub,
        'last_verified_by': ggrc_utils.last_verified_by_stub,
    }

    _api_attrs = reflection.ApiAttributes(
        'risk_type',
        'threat_source',
        'threat_event',
        'vulnerability',
        'external_id',
        'due_date',
        reflection.ExternalUserAttribute('created_by', force_create=True),
        reflection.ExternalUserAttribute('last_submitted_by',
                                         force_create=True),
        reflection.ExternalUserAttribute('last_verified_by',
                                         force_create=True),
        'last_submitted_at',
        'last_verified_at',
        'external_slug',
        'review_status',
        'review_status_display_name',
    )

    _aliases = {
        "description": {
            "display_name": "Description",
            "mandatory": True
        },
        "risk_type": {
            "display_name": "Risk Type",
            "mandatory": False
        },
        "threat_source": {
            "display_name": "Threat Source",
            "mandatory": False
        },
        "threat_event": {
            "display_name": "Threat Event",
            "mandatory": False
        },
        "vulnerability": {
            "display_name": "Vulnerability",
            "mandatory": False
        },
        "documents_file": None,
        "status": {
            "display_name":
            "State",
            "mandatory":
            False,
            "description":
            "Options are: \n {}".format('\n'.join(
                mixins.BusinessObject.VALID_STATES))
        },
        "review_status": {
            "display_name": "Review State",
            "mandatory": False,
            "filter_only": True,
        },
        "review_status_display_name": {
            "display_name": "Review Status",
            "mandatory": False,
        },
        "due_date": {
            "display_name": "Due Date",
            "mandatory": False,
        },
        "created_by": {
            "display_name": "Created By",
            "mandatory": False,
        },
        "last_submitted_at": {
            "display_name": "Last Owner Reviewed Date",
            "mandatory": False,
        },
        "last_submitted_by": {
            "display_name": "Last Owner Reviewed By",
            "mandatory": False,
        },
        "last_verified_at": {
            "display_name": "Last Compliance Reviewed Date",
            "mandatory": False,
        },
        "last_verified_by": {
            "display_name": "Last Compliance Reviewed By",
            "mandatory": False,
        },
    }

    def log_json(self):
        res = super(Risk, self).log_json()
        res["created_by"] = ggrc_utils.created_by_stub(self)
        res["last_submitted_by"] = ggrc_utils.last_submitted_by_stub(self)
        res["last_verified_by"] = ggrc_utils.last_verified_by_stub(self)
        return res