示例#1
0
    def custom_attributes(self, src):
        """Legacy setter for custom attribute values and definitions.

    This code should only be used for custom attribute definitions until
    setter for that is updated.
    """
        # pylint: disable=too-many-locals
        from ggrc.models.custom_attribute_value import CustomAttributeValue

        ca_values = src.get("custom_attribute_values")
        if ca_values and "attribute_value" in ca_values[0]:
            # This indicates that the new CA API is being used and the legacy API
            # should be ignored. If we need to use the legacy API the
            # custom_attribute_values property should contain stubs instead of entire
            # objects.
            return

        definitions = src.get("custom_attribute_definitions")
        if definitions is not None:
            self.process_definitions(definitions)

        attributes = src.get("custom_attributes")
        if not attributes:
            return

        old_values = collections.defaultdict(list)

        # attributes looks like this:
        #    [ {<id of attribute definition> : attribute value, ... }, ... ]

        # 1) Get all custom attribute values for the CustomAttributable instance
        attr_values = db.session.query(CustomAttributeValue).filter(
            and_(
                CustomAttributeValue.attributable_type ==
                self.__class__.__name__,
                CustomAttributeValue.attributable_id == self.id)).all()

        # Save previous value of custom attribute. This is a bit complicated by
        # the fact that imports can save multiple values at the time of writing.
        # old_values holds all previous values of attribute, last_values holds
        # chronologically last value.
        for value in attr_values:
            old_values[value.custom_attribute_id].append(
                (value.created_at, value.attribute_value))

        self._remove_existing_items(attr_values)

        # 4) Instantiate custom attribute values for each of the definitions
        #    passed in (keys)
        # pylint: disable=not-an-iterable
        # filter out attributes like Person:None
        attributes = {
            k: v
            for k, v in attributes.items() if v != "Person:None"
        }
        definitions = {
            d.id: d
            for d in self.get_custom_attribute_definitions()
        }
        for ad_id in attributes.keys():
            obj_type = self.__class__.__name__
            obj_id = self.id
            new_value = CustomAttributeValue(
                custom_attribute_id=int(ad_id),
                attributable=self,
                attribute_value=attributes[ad_id],
            )
            if definitions[int(ad_id)].attribute_type.startswith("Map:"):
                obj_type, obj_id = new_value.attribute_value.split(":")
                new_value.attribute_value = obj_type
                new_value.attribute_object_id = long(obj_id)
            elif definitions[int(ad_id)].attribute_type == "Checkbox":
                new_value.attribute_value = "1" if new_value.attribute_value else "0"
    def custom_attributes(self, src):
        """Legacy setter for custom attribute values and definitions.

    This code should only be used for custom attribute definitions until
    setter for that is updated.
    """
        from ggrc.models.custom_attribute_value import CustomAttributeValue
        from ggrc.services import signals

        ca_values = src.get("custom_attribute_values")
        if ca_values and "attribute_value" in ca_values[0]:
            # This indicates that the new CA API is being used and the legacy API
            # should be ignored. If we need to use the legacy API the
            # custom_attribute_values property should contain stubs instead of entire
            # objects.
            return

        definitions = src.get("custom_attribute_definitions")
        if definitions:
            self.process_definitions(definitions)

        attributes = src.get("custom_attributes")
        if not attributes:
            return

        old_values = collections.defaultdict(list)
        last_values = dict()

        # attributes looks like this:
        #    [ {<id of attribute definition> : attribute value, ... }, ... ]

        # 1) Get all custom attribute values for the CustomAttributable instance
        attr_values = db.session.query(CustomAttributeValue).filter(
            and_(
                CustomAttributeValue.attributable_type ==
                self.__class__.__name__,
                CustomAttributeValue.attributable_id == self.id)).all()

        # Save previous value of custom attribute. This is a bit complicated by
        # the fact that imports can save multiple values at the time of writing.
        # old_values holds all previous values of attribute, last_values holds
        # chronologically last value.
        for value in attr_values:
            old_values[value.custom_attribute_id].append(
                (value.created_at, value.attribute_value))

        last_values = {
            str(key): max(old_vals, key=lambda (created_at, _): created_at)
            for key, old_vals in old_values.iteritems()
        }

        self._remove_existing_items(attr_values)

        # 4) Instantiate custom attribute values for each of the definitions
        #    passed in (keys)
        # pylint: disable=not-an-iterable
        # filter out attributes like Person:None
        attributes = {
            k: v
            for k, v in attributes.items() if v != "Person:None"
        }
        definitions = {
            d.id: d
            for d in self.get_custom_attribute_definitions()
        }
        for ad_id in attributes.keys():
            obj_type = self.__class__.__name__
            obj_id = self.id
            new_value = CustomAttributeValue(
                custom_attribute_id=int(ad_id),
                attributable=self,
                attribute_value=attributes[ad_id],
            )
            if definitions[int(ad_id)].attribute_type.startswith("Map:"):
                obj_type, obj_id = new_value.attribute_value.split(":")
                new_value.attribute_value = obj_type
                new_value.attribute_object_id = long(obj_id)
            elif definitions[int(ad_id)].attribute_type == "Checkbox":
                new_value.attribute_value = "1" if new_value.attribute_value else "0"

            # 5) Set the context_id for each custom attribute value to the context id
            #    of the custom attributable.
            # TODO: We are ignoring contexts for now
            # new_value.context_id = cls.context_id

            # new value is appended to self.custom_attribute_values by the ORM
            # self.custom_attribute_values.append(new_value)
            if ad_id in last_values:
                _, previous_value = last_values[ad_id]
                if previous_value != attributes[ad_id]:
                    signals.Signals.custom_attribute_changed.send(
                        self.__class__,
                        obj=self,
                        src={
                            "type": obj_type,
                            "id": obj_id,
                            "operation": "UPDATE",
                            "value": new_value,
                            "old": previous_value
                        },
                        service=self.__class__.__name__)
            else:
                signals.Signals.custom_attribute_changed.send(
                    self.__class__,
                    obj=self,
                    src={
                        "type": obj_type,
                        "id": obj_id,
                        "operation": "INSERT",
                        "value": new_value,
                    },
                    service=self.__class__.__name__)
示例#3
0
  def custom_attributes(self, src):
    """Legacy setter for custom attribute values and definitions.

    This code should only be used for custom attribute definitions until
    setter for that is updated.
    """
    # pylint: disable=too-many-locals
    from ggrc.models.custom_attribute_value import CustomAttributeValue
    from ggrc.services import signals

    ca_values = src.get("custom_attribute_values")
    if ca_values and "attribute_value" in ca_values[0]:
      # This indicates that the new CA API is being used and the legacy API
      # should be ignored. If we need to use the legacy API the
      # custom_attribute_values property should contain stubs instead of entire
      # objects.
      return

    definitions = src.get("custom_attribute_definitions")
    if definitions is not None:
      self.process_definitions(definitions)

    attributes = src.get("custom_attributes")
    if not attributes:
      return

    old_values = collections.defaultdict(list)
    last_values = dict()

    # attributes looks like this:
    #    [ {<id of attribute definition> : attribute value, ... }, ... ]

    # 1) Get all custom attribute values for the CustomAttributable instance
    attr_values = db.session.query(CustomAttributeValue).filter(and_(
        CustomAttributeValue.attributable_type == self.__class__.__name__,
        CustomAttributeValue.attributable_id == self.id)).all()

    # Save previous value of custom attribute. This is a bit complicated by
    # the fact that imports can save multiple values at the time of writing.
    # old_values holds all previous values of attribute, last_values holds
    # chronologically last value.
    for value in attr_values:
      old_values[value.custom_attribute_id].append(
          (value.created_at, value.attribute_value))

    last_values = {str(key): max(old_vals,
                                 key=lambda (created_at, _): created_at)
                   for key, old_vals in old_values.iteritems()}

    self._remove_existing_items(attr_values)

    # 4) Instantiate custom attribute values for each of the definitions
    #    passed in (keys)
    # pylint: disable=not-an-iterable
    # filter out attributes like Person:None
    attributes = {k: v for k, v in attributes.items() if v != "Person:None"}
    definitions = {d.id: d for d in self.get_custom_attribute_definitions()}
    for ad_id in attributes.keys():
      obj_type = self.__class__.__name__
      obj_id = self.id
      new_value = CustomAttributeValue(
          custom_attribute_id=int(ad_id),
          attributable=self,
          attribute_value=attributes[ad_id],
      )
      if definitions[int(ad_id)].attribute_type.startswith("Map:"):
        obj_type, obj_id = new_value.attribute_value.split(":")
        new_value.attribute_value = obj_type
        new_value.attribute_object_id = long(obj_id)
      elif definitions[int(ad_id)].attribute_type == "Checkbox":
        new_value.attribute_value = "1" if new_value.attribute_value else "0"

      # 5) Set the context_id for each custom attribute value to the context id
      #    of the custom attributable.
      # TODO: We are ignoring contexts for now
      # new_value.context_id = cls.context_id

      # new value is appended to self.custom_attribute_values by the ORM
      # self.custom_attribute_values.append(new_value)
      if ad_id in last_values:
        _, previous_value = last_values[ad_id]
        if previous_value != attributes[ad_id]:
          signals.Signals.custom_attribute_changed.send(
              self.__class__,
              obj=self,
              src={
                  "type": obj_type,
                  "id": obj_id,
                  "operation": "UPDATE",
                  "value": new_value,
                  "old": previous_value
              }, service=self.__class__.__name__)
      else:
        signals.Signals.custom_attribute_changed.send(
            self.__class__,
            obj=self,
            src={
                "type": obj_type,
                "id": obj_id,
                "operation": "INSERT",
                "value": new_value,
            }, service=self.__class__.__name__)
示例#4
0
  def custom_attributes(self, src):
    """Legacy setter for custom attribute values and definitions.

    This code should only be used for custom attribute definitions until
    setter for that is updated.
    """
    # pylint: disable=too-many-locals
    from ggrc.models.custom_attribute_value import CustomAttributeValue

    ca_values = src.get("custom_attribute_values")
    if ca_values and "attribute_value" in ca_values[0]:
      # This indicates that the new CA API is being used and the legacy API
      # should be ignored. If we need to use the legacy API the
      # custom_attribute_values property should contain stubs instead of entire
      # objects.
      return

    definitions = src.get("custom_attribute_definitions")
    if definitions is not None:
      self.process_definitions(definitions)

    attributes = src.get("custom_attributes")
    if not attributes:
      return

    old_values = collections.defaultdict(list)

    # attributes looks like this:
    #    [ {<id of attribute definition> : attribute value, ... }, ... ]

    # 1) Get all custom attribute values for the CustomAttributable instance
    attr_values = db.session.query(CustomAttributeValue).filter(and_(
        CustomAttributeValue.attributable_type == self.__class__.__name__,
        CustomAttributeValue.attributable_id == self.id)).all()

    # Save previous value of custom attribute. This is a bit complicated by
    # the fact that imports can save multiple values at the time of writing.
    # old_values holds all previous values of attribute, last_values holds
    # chronologically last value.
    for value in attr_values:
      old_values[value.custom_attribute_id].append(
          (value.created_at, value.attribute_value))

    self._remove_existing_items(attr_values)

    # 4) Instantiate custom attribute values for each of the definitions
    #    passed in (keys)
    # pylint: disable=not-an-iterable
    # filter out attributes like Person:None
    attributes = {k: v for k, v in attributes.items() if v != "Person:None"}
    definitions = {d.id: d for d in self.get_custom_attribute_definitions()}
    for ad_id in attributes.keys():
      obj_type = self.__class__.__name__
      obj_id = self.id
      new_value = CustomAttributeValue(
          custom_attribute_id=int(ad_id),
          attributable=self,
          attribute_value=attributes[ad_id],
      )
      if definitions[int(ad_id)].attribute_type.startswith("Map:"):
        obj_type, obj_id = new_value.attribute_value.split(":")
        new_value.attribute_value = obj_type
        new_value.attribute_object_id = long(obj_id)
      elif definitions[int(ad_id)].attribute_type == "Checkbox":
        new_value.attribute_value = "1" if new_value.attribute_value else "0"
示例#5
0
  def custom_attributes(self, src):
    """Legacy setter for custom attribute values and definitions.

    This code should only be used for custom attribute definitions until
    setter for that is updated.
    """
    from ggrc.fulltext.mysql import MysqlRecordProperty
    from ggrc.models.custom_attribute_value import CustomAttributeValue
    from ggrc.services import signals

    ca_values = src.get("custom_attribute_values")
    if ca_values and "attribute_value" in ca_values[0]:
      # This indicates that the new CA API is being used and the legacy API
      # should be ignored. If we need to use the legacy API the
      # custom_attribute_values property should contain stubs instead of entire
      # objects.
      return

    definitions = src.get("custom_attribute_definitions")
    if definitions:
      self.process_definitions(definitions)

    attributes = src.get("custom_attributes")
    if not attributes:
      return

    old_values = collections.defaultdict(list)
    last_values = dict()

    # attributes looks like this:
    #    [ {<id of attribute definition> : attribute value, ... }, ... ]

    # 1) Get all custom attribute values for the CustomAttributable instance
    attr_values = db.session.query(CustomAttributeValue).filter(and_(
        CustomAttributeValue.attributable_type == self.__class__.__name__,
        CustomAttributeValue.attributable_id == self.id)).all()

    attr_value_ids = [value.id for value in attr_values]
    ftrp_properties = [
        "attribute_value_{id}".format(id=_id) for _id in attr_value_ids]

    # Save previous value of custom attribute. This is a bit complicated by
    # the fact that imports can save multiple values at the time of writing.
    # old_values holds all previous values of attribute, last_values holds
    # chronologically last value.
    for value in attr_values:
      old_values[value.custom_attribute_id].append(
          (value.created_at, value.attribute_value))

    last_values = {str(key): max(old_vals,
                                 key=lambda (created_at, _): created_at)
                   for key, old_vals in old_values.iteritems()}

    # 2) Delete all fulltext_record_properties for the list of values
    if len(attr_value_ids) > 0:
      db.session.query(MysqlRecordProperty)\
          .filter(
              and_(
                  MysqlRecordProperty.type == self.__class__.__name__,
                  MysqlRecordProperty.property.in_(ftrp_properties)))\
          .delete(synchronize_session='fetch')

      # 3) Delete the list of custom attribute values
      db.session.query(CustomAttributeValue)\
          .filter(CustomAttributeValue.id.in_(attr_value_ids))\
          .delete(synchronize_session='fetch')

      db.session.commit()

    # 4) Instantiate custom attribute values for each of the definitions
    #    passed in (keys)
    # pylint: disable=not-an-iterable
    definitions = {d.id: d for d in self.get_custom_attribute_definitions()}
    for ad_id in attributes.keys():
      obj_type = self.__class__.__name__
      obj_id = self.id
      new_value = CustomAttributeValue(
          custom_attribute_id=ad_id,
          attributable=self,
          attribute_value=attributes[ad_id],
      )
      if definitions[int(ad_id)].attribute_type.startswith("Map:"):
        obj_type, obj_id = new_value.attribute_value.split(":")
        new_value.attribute_value = obj_type
        new_value.attribute_object_id = long(obj_id)
      # 5) Set the context_id for each custom attribute value to the context id
      #    of the custom attributable.
      # TODO: We are ignoring contexts for now
      # new_value.context_id = cls.context_id
      self.custom_attribute_values.append(new_value)
      if ad_id in last_values:
        _, previous_value = last_values[ad_id]
        if previous_value != attributes[ad_id]:
          signals.Signals.custom_attribute_changed.send(
              self.__class__,
              obj=self,
              src={
                  "type": obj_type,
                  "id": obj_id,
                  "operation": "UPDATE",
                  "value": new_value,
                  "old": previous_value
              }, service=self.__class__.__name__)
      else:
        signals.Signals.custom_attribute_changed.send(
            self.__class__,
            obj=self,
            src={
                "type": obj_type,
                "id": obj_id,
                "operation": "INSERT",
                "value": new_value,
            }, service=self.__class__.__name__)