Exemple #1
0
 def wrapper(*args, **kwargs):
   """Wrapper procedure."""
   process_user_id = kwargs.get("id")
   curent_user_id = login.get_current_user_id()
   if curent_user_id != process_user_id:
     raise Forbidden()
   return procedure(*args, **kwargs)
Exemple #2
0
def log_event(session, obj=None, current_user_id=None):
    revisions = []
    session.flush()
    if current_user_id is None:
        current_user_id = get_current_user_id()
    cache = get_cache()
    for o in cache.dirty:
        revision = Revision(o, current_user_id, "modified", o.to_json())
        revisions.append(revision)
    for o in cache.deleted:
        revision = Revision(o, current_user_id, "deleted", o.to_json())
        revisions.append(revision)
    for o in cache.new:
        revision = Revision(o, current_user_id, "created", o.to_json())
        revisions.append(revision)
    if obj is None:
        resource_id = 0
        resource_type = None
        action = "IMPORT"
    else:
        resource_id = obj.id
        resource_type = str(obj.__class__.__name__)
        action = request.method
    if revisions:
        event = Event(
            modified_by_id=current_user_id, action=action, resource_id=resource_id, resource_type=resource_type
        )
        event.revisions = revisions
        session.add(event)
Exemple #3
0
 def _do_update_collection(cls, obj, value, attr_name):
   """Special logic to update relationship collection."""
   # SQLAlchemy instrumentation botches up if we replace entire collections
   # It works if we update them with changes
   new_set = set(value)
   old_set = set(getattr(obj, attr_name))
   coll_class_attr = getattr(obj.__class__, attr_name)
   coll_attr = getattr(obj, attr_name)
   # Join table objects require special handling so that we can be sure to
   # set the modified_by_id correctly
   if isinstance(coll_class_attr, AssociationProxy):
     current_user_id = get_current_user_id()
     proxied_attr = coll_class_attr.local_attr
     proxied_property = coll_class_attr.remote_attr
     proxied_set_map = dict([(getattr(i, proxied_property.key), i)
                             for i in getattr(obj, proxied_attr.key)])
     coll_attr = getattr(obj, proxied_attr.key)
     for item in new_set - old_set:
       new_item = coll_class_attr.creator(item)
       new_item.modified_by_id = current_user_id
       coll_attr.append(new_item)
     for item in old_set - new_set:
       coll_attr.remove(proxied_set_map[item])
   else:
     for item in new_set - old_set:
       coll_attr.append(item)
     for item in old_set - new_set:
       coll_attr.remove(item)
Exemple #4
0
def _copy_snapshot_relationships(*_, **kwargs):
  """Add relationships between snapshotted objects.

  Create relationships between new snapshot and other snapshots
  if a relationship exists between a pair of object that was snapshotted.
  """
  query = """
      INSERT IGNORE INTO relationships (
          modified_by_id, created_at, updated_at, source_id, source_type,
          destination_id, destination_type, context_id
      )
      SELECT
          :user_id, now(), now(), s_1.id, "Snapshot",
          s_2.id, "Snapshot", s_2.context_id
      FROM relationships AS rel
      INNER JOIN snapshots AS s_1
          ON (s_1.child_type, s_1.child_id) =
             (rel.source_type, rel.source_id)
      INNER JOIN snapshots AS s_2
          ON (s_2.child_type, s_2.child_id) =
             (rel.destination_type, rel.destination_id)
      WHERE
          s_1.parent_id = :parent_id AND
          s_2.parent_id = :parent_id AND
          (s_1.id = :snapshot_id OR s_2.id = :snapshot_id)
      """
  db.session.execute(query, {
      "user_id": get_current_user_id(),
      "parent_id": kwargs.get("obj").parent.id,
      "snapshot_id": kwargs.get("obj").id
  })
Exemple #5
0
def relate_assignees(assessment, snapshot, template, audit):
  """Generates assignee list and relates them to Assessment objects

    Args:
        assessment (model instance): Assessment model
        snapshot (model instance): Snapshot,
        template (model instance): AssessmentTemplate model nullable,
        audit (model instance): Audit
  """
  if template:
    template_settings = template.default_people
  else:
    template_settings = {"assignees": "Principal Assignees",
                         "verifiers": "Auditors"}
  acl_dict = generate_role_object_dict(snapshot, audit)
  assignee_ids = get_people_ids_based_on_role("assignees",
                                              "Audit Lead",  # default assignee
                                              template_settings,
                                              acl_dict)
  verifier_ids = get_people_ids_based_on_role("verifiers",
                                              "Auditors",  # default verifier
                                              template_settings,
                                              acl_dict)
  generate_assignee_relations(assessment,
                              assignee_ids,
                              verifier_ids,
                              [get_current_user_id()])
Exemple #6
0
def _insert_program_relationships(relationship_stubs):
  """Insert missing obj-program relationships."""
  if not relationship_stubs:
    return
  current_user_id = get_current_user_id()
  now = datetime.now()
  # We are doing an INSERT IGNORE INTO here to mitigate a race condition
  # that happens when multiple simultaneous requests create the same
  # automapping. If a relationship object fails our unique constraint
  # it means that the mapping was already created by another request
  # and we can safely ignore it.
  inserter = relationship.Relationship.__table__.insert().prefix_with(
      "IGNORE")
  db.session.execute(
      inserter.values([
          {
              "id": None,
              "modified_by_id": current_user_id,
              "created_at": now,
              "updated_at": now,
              "source_type": relationship_stub.source_type,
              "source_id": relationship_stub.source_id,
              "destination_type": relationship_stub.destination_type,
              "destination_id": relationship_stub.destination_id,
              "context_id": None,
              "status": None,
              "parent_id": None,
              "is_external": False,
          }
          for relationship_stub in relationship_stubs
      ])
  )
def get_attributes_data(computed_values):
  """Store computed values in the database."""
  data = []
  user_id = login.get_current_user_id()
  for attr, objects in computed_values.iteritems():
    aggregate_type = get_aggregate_type(attr)
    aggregate_field = get_aggregate_field(attr)
    definition_id = attr.attribute_definition.attribute_definition_id
    for obj, computed_value in objects.iteritems():
      data.append({
          "object_type": obj[0],
          "object_id": obj[1],
          "source_type": aggregate_type,
          "source_id": computed_value["source_id"],
          "source_attr": aggregate_field,
          "value_datetime": computed_value["value_datetime"],
          "value_string": computed_value["value_string"] or "",
          "value_integer": computed_value["value_integer"],
          "attribute_template_id": attr.attribute_template_id,
          "attribute_definition_id": definition_id,
          "created_at": datetime.datetime.utcnow(),
          "updated_at": datetime.datetime.utcnow(),
          "created_by_id": user_id,
          "updated_by_id": user_id,
      })
  return data
Exemple #8
0
  def parse_item(self):
    """Parse document link lines.

    Returns:
      list of documents for all URLs and evidences.
    """
    documents = []
    if self.raw_value:
      seen_links = set()
      duplicate_inks = set()
      user_id = get_current_user_id()
      for line in self.raw_value.splitlines():
        link = line.strip()
        if not link:
          continue

        if link not in seen_links:
          seen_links.add(link)
          documents.append(self.build_document(link, user_id))
        else:
          duplicate_inks.add(link)

      if duplicate_inks:
        # NOTE: We rely on the fact that links in duplicate_inks are all
        # instances of unicode (if that assumption breaks, unicode
        # encode/decode errors can occur for non-ascii link values)
        self.add_warning(errors.DUPLICATE_IN_MULTI_VALUE,
                         column_name=self.display_name,
                         duplicates=u", ".join(sorted(duplicate_inks)))

    return documents
Exemple #9
0
  def _my_work_count(self, **kwargs):  # pylint: disable=unused-argument
    """Get object counts for my work page."""
    with benchmark("Make response"):
      aliased = my_objects.get_myobjects_query(
          types=self.MY_WORK_OBJECTS.keys(),
          contact_id=login.get_current_user_id()
      )
      all_ = db.session.query(
          aliased.c.type,
          aliased.c.id,
      )

      all_ids = collections.defaultdict(set)
      for type_, id_ in all_:
        all_ids[type_].add(id_)

      response_object = self.MY_WORK_OBJECTS.copy()
      for type_, ids in all_ids.items():
        model = models.get_model(type_)
        # pylint: disable=protected-access
        # We must move the type permissions query to a proper utility function
        # but we will not do that for a patch release
        permission_filter = builder.QueryHelper._get_type_query(model, "read")
        if permission_filter is not None:
          count = model.query.filter(
              model.id.in_(ids),
              permission_filter,
          ).count()
        else:
          count = model.query.filter(model.id.in_(ids)).count()
        response_object[type_] = count

      return self.json_success_response(response_object, )
  def current_user_wfo_or_assignee(self):
    """Current user is Workflow owner or Assignee for self."""
    current_user_id = login.get_current_user_id()

    # pylint: disable=not-an-iterable
    return (current_user_id == self.contact_id or
            current_user_id in [ur.person_id for ur in self.wfo_roles])
Exemple #11
0
  def _get_assessments(self, model, object_type, object_id):
    """Get a list of assessments.

    Get a list of assessments with all their data from the db, according to the
    request GET parameters.
    """

    ids_query = model.get_similar_objects_query(object_id, "Assessment")
    order_by = self._get_order_by_parameter()
    limit = self._get_limit_parameters()

    if not permissions.has_system_wide_read():
      if not permissions.is_allowed_read(object_type, object_id, None):
        raise Forbidden()
      acl = models.all_models.AccessControlList
      acr = models.all_models.AccessControlRole
      ids_query = db.session.query(acl.object_id).join(acr).filter(
          acr.read == 1,
          acl.object_type == "Assessment",
          acl.person_id == get_current_user_id(),
          acl.object_id.in_(ids_query),
      )

    query = models.Assessment.query.options(
        orm.Load(models.Assessment).undefer_group(
            "Assessment_complete",
        ),
        orm.Load(models.Assessment).joinedload(
            "audit"
        ).undefer_group(
            "Audit_complete",
        ),
        orm.Load(models.Assessment).joinedload(
            "custom_attribute_definitions"
        ).undefer_group(
            "CustomAttributeDefinitons_complete",
        ),
        orm.Load(models.Assessment).joinedload(
            "custom_attribute_values"
        ).undefer_group(
            "CustomAttributeValues_complete",
        ),
    ).filter(
        models.Assessment.id.in_(ids_query)
    )
    if order_by:
      query = pagination.apply_order_by(
          models.Assessment,
          query,
          order_by,
          models.Assessment,
      )
    total = query.count()
    if limit:
      query = pagination.apply_limit(query, limit)
    # note that using pagination.get_total_count here would return wrong counts
    # due to query being an eager query.

    return query.all(), total
Exemple #12
0
def get_value(people_group, audit, obj, template=None):
  """Return the people related to an Audit belonging to the given role group.

  Args:
    people_group: (string) the name of the group of people to return,
      e.g. "assessors"
    template: (ggrc.models.AssessmentTemplate) a template to take into
      consideration
    audit: (ggrc.models.Audit) an audit instance
    obj: an object related to `audit`, can be anything that can be mapped
      to an Audit, e.g. Control, Issue, Facility, etc.
  Returns:
    Either a Person object, a list of Person objects, or None if no people
    matching the criteria are found.
  """
  auditors = (
      user_role.person for user_role in audit.context.user_roles
      if user_role.role.name == u"Auditor"
  )

  if not template:
    if people_group == "creator":
      # don't use get_current_user because that returns a proxy
      return Person.query.get(get_current_user_id())
    elif people_group == "assessors":
      return list(auditors)

    return None

  types = {
      "Object Owners": [
          get_by_id(owner)
          for owner in obj.revision.content.get("owners", [])
      ],
      "Audit Lead": getattr(audit, "contact", None),
      "Primary Contact": get_by_id(obj.revision.content.get("contact")),
      "Secondary Contact": get_by_id(
          obj.revision.content.get("secondary_contact")),
      "Primary Assessor": get_by_id(
          obj.revision.content.get("principal_assessor")),
      "Secondary Assessor": get_by_id(
          obj.revision.content.get("secondary_assessor")),
  }
  people = template.default_people.get(people_group)
  if not people:
    return None

  if isinstance(people, list):
    return [get_by_id({
        'type': 'Person',
        'id': person_id
    }) for person_id in people]

  # only consume the generator if it will be used in the return value
  if people == u"Auditors":
    types[u"Auditors"] = list(auditors)

  return types.get(people)
Exemple #13
0
def find_users(emails):
  """Find or generate user.

  If Integration Server is specified not found in DB user is generated
  with Creator role.
  """
  # pylint: disable=too-many-locals
  if not settings.INTEGRATION_SERVICE_URL:
    return Person.query.filter(Person.email.in_(emails)).options(
        orm.undefer_group('Person_complete')).all()

  # Verify emails
  usernames = [email.split('@')[0] for email in emails
               if is_authorized_domain(email) and
               not is_external_app_user_email(email)]

  service = client.PersonClient()
  ldaps = service.search_persons(usernames)

  authorized_domain = getattr(settings, "AUTHORIZED_DOMAIN", "")
  verified_emails = {'%s@%s' % (ldap['username'], authorized_domain)
                     for ldap in ldaps}

  # Find users in db
  users = Person.query.filter(Person.email.in_(emails)).all()
  found_emails = {user.email for user in users}

  # Create new users
  new_emails = verified_emails - found_emails
  new_usernames = [email.split('@')[0] for email in new_emails]
  new_users = [('%s@%s' % (ldap['username'], authorized_domain),
                '%s %s' % (ldap['firstName'], ldap['lastName']))
               for ldap in ldaps if ldap['username'] in new_usernames]

  for email, name in new_users:
    user = create_user(email,
                       name=name,
                       modified_by_id=get_current_user_id())
    users.append(user)

  # bulk create people
  if new_users:
    log_event(db.session)
    db.session.commit()

  creator_role_granted = False
  # Grant Creator role to all users
  for user in users:
    if user.system_wide_role == SystemWideRoles.NO_ACCESS:
      add_creator_role(user)
      creator_role_granted = True

  # bulk create people roles
  if creator_role_granted:
    log_event(db.session)
    db.session.commit()

  return users
Exemple #14
0
  def _flush(self, parent_relationship):
    """Manually INSERT generated automappings."""
    if not self.auto_mappings:
      return
    with benchmark("Automapping flush"):
      current_user_id = login.get_current_user_id()
      automapping_result = db.session.execute(
          Automapping.__table__.insert().values(
              relationship_id=parent_relationship.id,
              source_id=parent_relationship.source_id,
              source_type=parent_relationship.source_type,
              destination_id=parent_relationship.destination_id,
              destination_type=parent_relationship.destination_type,
          )
      )
      automapping_id = automapping_result.inserted_primary_key[0]
      self.automapping_ids.add(automapping_id)
      now = datetime.utcnow()
      # We are doing an INSERT IGNORE INTO here to mitigate a race condition
      # that happens when multiple simultaneous requests create the same
      # automapping. If a relationship object fails our unique constraint
      # it means that the mapping was already created by another request
      # and we can safely ignore it.
      inserter = Relationship.__table__.insert().prefix_with("IGNORE")
      original = self.order(Stub.from_source(parent_relationship),
                            Stub.from_destination(parent_relationship))
      db.session.execute(inserter.values([{
          "id": None,
          "modified_by_id": current_user_id,
          "created_at": now,
          "updated_at": now,
          "source_id": src.id,
          "source_type": src.type,
          "destination_id": dst.id,
          "destination_type": dst.type,
          "context_id": None,
          "status": None,
          "parent_id": parent_relationship.id,
          "automapping_id": automapping_id,
          "is_external": False}
          for src, dst in self.auto_mappings
          if (src, dst) != original]))  # (src, dst) is sorted

      self._set_audit_id_for_issues(automapping_id)

      cache = Cache.get_cache(create=True)
      if cache:
        # Add inserted relationships into new objects collection of the cache,
        # so that they will be logged within event and appropriate revisions
        # will be created.
        cache.new.update(
            (relationship, relationship.log_json())
            for relationship in Relationship.query.filter_by(
                automapping_id=automapping_id,
            )
        )
Exemple #15
0
 def handle_comment_post(sender, objects=None, **kwargs):
   """Save information on which user created the Comment object."""
   # pylint: disable=unused-argument
   creator_id = get_current_user_id()
   for obj in objects:
     obj_owner = ObjectOwner(
         person_id=creator_id,
         ownable=obj,
     )
     db.session.add(obj_owner)
Exemple #16
0
 def set_obj_attr(self):
   """ Create comments """
   if self.dry_run or not self.value:
     return
   current_obj = self.row_converter.obj
   for description in self.value:
     comment = Comment(description=description,
                       modified_by_id=get_current_user_id())
     db.session.add(comment)
     mapping = Relationship(source=current_obj, destination=comment)
     db.session.add(mapping)
Exemple #17
0
def find_or_create_user_by_email(email, name):
  """Generates or find user for selected email."""
  user = find_user_by_email(email)
  if not user:
    user = create_user(email,
                       name=name,
                       modified_by_id=get_current_user_id())
  if is_authorized_domain(email) and \
     user.system_wide_role == SystemWideRoles.NO_ACCESS:
    add_creator_role(user)
  return user
Exemple #18
0
def _rel_child(parent_acl_ids, source=True):
  """Get left side of relationships mappings through source."""
  rel_table = all_models.Relationship.__table__
  acl_table = all_models.AccessControlList.__table__
  parent_acr = all_models.AccessControlRole.__table__.alias(
      "parent_acr_{}".format(source)
  )
  child_acr = all_models.AccessControlRole.__table__.alias(
      "child_acr_{}".format(source)
  )

  if source:
    object_id = rel_table.c.destination_id
    object_type = rel_table.c.destination_type
  else:
    object_id = rel_table.c.source_id
    object_type = rel_table.c.source_type

  acl_link = sa.and_(
      acl_table.c.object_id == rel_table.c.id,
      acl_table.c.object_type == all_models.Relationship.__name__,
  )

  select_statement = sa.select([
      acl_table.c.person_id.label("person_id"),
      child_acr.c.id.label("ac_role_id"),
      object_id.label("object_id"),
      object_type.label("object_type"),
      sa.func.now().label("created_at"),
      sa.literal(login.get_current_user_id()).label("modified_by_id"),
      sa.func.now().label("updated_at"),
      acl_table.c.id.label("parent_id"),
      acl_table.c.id.label("parent_id_nn"),
  ]).select_from(
      sa.join(
          sa.join(
              sa.join(
                  rel_table,
                  acl_table,
                  acl_link
              ),
              parent_acr,
              parent_acr.c.id == acl_table.c.ac_role_id
          ),
          child_acr,
          child_acr.c.parent_id == parent_acr.c.id
      )
  ).where(
      sa.and_(
          acl_table.c.id.in_(parent_acl_ids),
          child_acr.c.object_type == object_type,
      )
  )
  return select_statement
 def handle_cad_delete(sender, obj, src=None, service=None):
   """Make sure create revision after deleting CAD from admin panel"""
   # pylint: disable=unused-argument
   now = datetime.datetime.utcnow()
   current_user_id = get_current_user_id()
   for model in all_models.all_models:
     if model._inflector.table_singular != obj.definition_type:
       continue
     for instance in model.eager_query():
       instance.updated_at = now
       instance.modified_by_id = current_user_id
     return
Exemple #20
0
def do_missing_revisions():
  """Crate 'created/modified' revisions.

  Iterate thought objects in objects_without_revisions
  table and create revisions
  """
  event = all_models.Event(action="BULK")
  db.session.add(event)
  db.session.commit()
  revisions_table = all_models.Revision.__table__
  count = _get_new_objects_count()
  chunk_size = 100
  logger.info("Crating revision content...")
  for index, chunk in enumerate(_get_chunks(_get_new_objects(),
                                            chunk_size), 1):
    logger.info("Processing chunk %s of %s", index, count / chunk_size + 1)
    revisions = []
    for obj_id, obj_type, action in chunk:
      model = getattr(all_models, obj_type, None)
      if not model:
        logger.warning("Failed to update revisions"
                       " for invalid model: %s", obj_type)
        continue

      if not hasattr(model, "log_json"):
        logger.warning("Model '%s' has no log_json method,"
                       " revision generation skipped", obj_type)
        continue
      obj = model.query.get(obj_id)
      if not obj:
        logger.info("Object '%s' with id '%s' does't exists,"
                    " revision generation skipped", obj_type, obj_id)
        continue

      obj_content = obj.log_json()
      revisions.append({
          "resource_id": obj_id,
          "resource_type": obj_type,
          "resource_slug": obj_content.get("slug"),
          "event_id": event.id,
          "action": action,
          "content": obj_content,
          "context_id": obj_content.get("context_id"),
          "modified_by_id": (obj_content.get("modified_by_id") or
                             get_current_user_id()),
          "source_type": obj_content.get("source_type"),
          "source_id": obj_content.get("source_id"),
          "destination_type": obj_content.get("destination_type"),
          "destination_id": obj_content.get("destination_id")
      })
    db.session.execute(revisions_table.insert(), revisions)
    db.session.commit()
  db.session.execute("truncate objects_without_revisions")
Exemple #21
0
def find_or_create_user_by_email(email, name, modifier=None):
  """Generates or find user for selected email."""
  user = find_user_by_email(email)
  if not user:
    _, app_email = parseaddr(settings.EXTERNAL_APP_USER)

    if not modifier and email != app_email:
      modifier = get_current_user_id()
    user = create_user(email, name=name, modified_by_id=modifier)
  if is_authorized_domain(email) and \
     user.system_wide_role == SystemWideRoles.NO_ACCESS:
    add_creator_role(user, modified_by_id=modifier)
  return user
Exemple #22
0
def _propagate_to_wf_children(new_wf_acls, child_class):
  """Propagate newly added roles to workflow objects.

  Args:
    wf_new_acl: list of all newly created acl entries for workflows

  Returns:
    list of newly created acl entries for task groups.
  """

  child_table = child_class.__table__
  acl_table = all_models.AccessControlList.__table__
  acr_table = all_models.AccessControlRole.__table__.alias("parent_acr")
  acr_mapped_table = all_models.AccessControlRole.__table__.alias("mapped")

  current_user_id = login.get_current_user_id()

  select_statement = sa.select([
      acl_table.c.person_id,
      acr_mapped_table.c.id,
      child_table.c.id,
      sa.literal(child_class.__name__),
      sa.func.now(),
      sa.literal(current_user_id),
      sa.func.now(),
      acl_table.c.id.label("parent_id"),
      acl_table.c.id.label("parent_id_nn"),
  ]).select_from(
      sa.join(
          sa.join(
              sa.join(
                  child_table,
                  acl_table,
                  sa.and_(
                      acl_table.c.object_id == child_table.c.workflow_id,
                      acl_table.c.object_type == all_models.Workflow.__name__,
                  )
              ),
              acr_table,
          ),
          acr_mapped_table,
          acr_mapped_table.c.name == sa.func.concat(
              acr_table.c.name, " Mapped")
      )
  ).where(
      acl_table.c.id.in_(new_wf_acls)
  )

  acl_utils.insert_select_acls(select_statement)

  return _get_child_ids(new_wf_acls, child_class)
Exemple #23
0
  def _create_audit_relationships(self):
    """Create relationships between snapshot objects and audits.

    Generally snapshots are related to audits by default, but we also duplicate
    this data in relationships table for ACL propagation.
    """

    relationships_table = all_models.Relationship.__table__
    snapshot_table = all_models.Snapshot.__table__
    inserter = relationships_table.insert().prefix_with("IGNORE")

    audit_ids = {parent.id for parent in self.parents}
    if not audit_ids:
      return

    old_ids = self._get_audit_relationships(audit_ids)

    select_statement = sa.select([
        sa.literal(get_current_user_id()),
        sa.func.now(),
        sa.func.now(),
        snapshot_table.c.parent_id,
        snapshot_table.c.parent_type,
        snapshot_table.c.id,
        sa.literal(all_models.Snapshot.__name__),
    ]).select_from(
        snapshot_table
    ).where(
        snapshot_table.c.parent_id.in_(audit_ids)
    )

    db.session.execute(
        inserter.from_select(
            [
                relationships_table.c.modified_by_id,
                relationships_table.c.created_at,
                relationships_table.c.updated_at,
                relationships_table.c.source_id,
                relationships_table.c.source_type,
                relationships_table.c.destination_id,
                relationships_table.c.destination_type,
            ],
            select_statement
        )
    )

    new_ids = self._get_audit_relationships(audit_ids)
    created_ids = new_ids.difference(old_ids)
    acl.add_relationships(created_ids)
Exemple #24
0
def start_update_cad_related_objs(event_id, model_name, need_revisions=None):
  """Start a background task to update related objects of CAD."""
  background_task.create_task(
      name="update_cad_related_objects",
      url=flask.url_for(update_cad_related_objects.__name__),
      parameters={
          "event_id": event_id,
          "model_name": model_name,
          "modified_by_id": login.get_current_user_id(),
          "need_revisions": need_revisions,
      },
      method="POST",
      queued_callback=update_cad_related_objects
  )
  db.session.commit()
Exemple #25
0
  def get_or_generate_object(self, attr_name):
    """Fetch an existing object if possible or create and return a new one.

    Note: Person object is the only exception here since it does not have a
    slug field.
    """
    value = self.get_value(attr_name)
    new_objects = self.block_converter.converter.new_objects[self.object_class]
    if value in new_objects:
      return new_objects[value]
    obj = self.get_object_by_key(attr_name)
    if value:
      new_objects[value] = obj
    obj.modified_by_id = get_current_user_id()
    return obj
Exemple #26
0
  def set_obj_attr(self):
    """ Create comments """
    if self.dry_run or not self.value:
      return
    current_obj = self.row_converter.obj
    for description in self.value:
      if current_obj.access_control_list:
        current_user = get_current_user()
        assignee_types = [acl.ac_role.name
                          for person, acl in current_obj.access_control_list
                          if person == current_user]
        assignee_type = ','.join(assignee_types)
        comment = all_models.Comment(description=description,
                                     modified_by_id=get_current_user_id(),
                                     assignee_type=assignee_type)
      else:
        comment = all_models.Comment(description=description,
                                     modified_by_id=get_current_user_id())

      db.session.add(comment)
      mapping = all_models.Relationship(source=current_obj,
                                        destination=comment)
      db.session.add(mapping)
      self.row_converter.comments.append(comment)
Exemple #27
0
def add_notification(obj, notif_type_name):
    """Add notification for object uses notif_type_cache as cache"""
    from ggrc.models import all_models
    notif_type_id = all_models.NotificationType.query.filter_by(
        name=notif_type_name).one().id

    # I don't like to have flush here, but we need a ID for newly created objects
    if not obj.id:
        db.session.flush()

    db.session.add(
        all_models.Notification(object=obj,
                                send_on=datetime.datetime.utcnow(),
                                notification_type_id=notif_type_id,
                                runner=all_models.Notification.RUNNER_FAST,
                                modified_by_id=get_current_user_id()))
Exemple #28
0
    def _handle_raw_data(self):
        """Pass raw values into column handlers for all cell in the row."""

        row_headers = {
            attr_name: (idx, header_dict)
            for idx, (attr_name,
                      header_dict) in enumerate(self.headers.iteritems())
        }
        if self.object_class == all_models.Comment:
            self.obj = all_models.Comment(modified_by_id=get_current_user_id())

        for attr_name in self.block_converter.handle_fields:
            if attr_name not in row_headers or self.is_delete:
                continue
            idx, header_dict = row_headers[attr_name]
            self.handle_raw_cell(attr_name, idx, header_dict)
Exemple #29
0
    def get_or_generate_object(self, attr_name):
        """Fetch an existing object if possible or create and return a new one.

    Note: Person object is the only exception here since it does not have a
    slug field.
    """
        value = self.get_value(attr_name)
        new_objects = self.block_converter.converter.new_objects[
            self.object_class]
        if value in new_objects:
            return new_objects[value]
        obj = self.get_object_by_key(attr_name)
        if value:
            new_objects[value] = obj
        obj.modified_by_id = get_current_user_id()
        return obj
Exemple #30
0
def find_users(emails):
    """Find or generate user.

  If Integration Server is specified not found in DB user is generated
  with Creator role.
  """
    if not settings.INTEGRATION_SERVICE_URL:
        return Person.query.filter(Person.email.in_(emails)).options(
            orm.undefer_group('Person_complete')).all()

    # Verify emails
    usernames = [
        email.split('@')[0] for email in emails if is_authorized_domain(email)
    ]

    service = client.PersonClient()
    ldaps = service.search_persons(usernames)

    authorized_domain = getattr(settings, "AUTHORIZED_DOMAIN", "")
    verified_emails = {
        '%s@%s' % (ldap['username'], authorized_domain)
        for ldap in ldaps
    }

    # Find users in db
    users = Person.query.filter(Person.email.in_(emails)).all()
    found_emails = {user.email for user in users}

    # Create new users
    new_emails = verified_emails - found_emails
    new_usernames = [email.split('@')[0] for email in new_emails]
    new_users = [('%s@%s' % (ldap['username'], authorized_domain),
                  '%s %s' % (ldap['firstName'], ldap['lastName']))
                 for ldap in ldaps if ldap['username'] in new_usernames]

    for email, name in new_users:
        user = create_user(email,
                           name=name,
                           modified_by_id=get_current_user_id())
        users.append(user)

    # Grant Creator role to all users
    for user in users:
        if user.system_wide_role == SystemWideRoles.NO_ACCESS:
            add_creator_role(user)

    return users
Exemple #31
0
def _recover_create_revisions(revisions_table, event, object_type,
                              chunk_without_revisions):
    """Log a "created"/"modified" revision for every passed object's json.

  If json["updated_at"] == json["created_at"], log action="created".
  If json["updated_at"] != json["created_at"], log action="modified".
  """
    def determine_action(obj_content):
        if obj_content.get("created_at") != obj_content.get("updated_at"):
            return "modified"
        else:
            return "created"

    # Every object with id not present in obj_
    object_ids_with_jsons = [(obj.id, obj.log_json())
                             for obj in chunk_without_revisions]

    if not object_ids_with_jsons:
        return

    db.session.execute(
        revisions_table.insert(),
        [{
            "resource_id":
            obj_id,
            "resource_type":
            object_type,
            "event_id":
            event.id,
            "action":
            determine_action(obj_content),
            "content":
            obj_content,
            "context_id":
            obj_content.get("context_id"),
            "modified_by_id":
            (obj_content.get("modified_by_id") or get_current_user_id()),
            "source_type":
            obj_content.get("source_type"),
            "source_id":
            obj_content.get("source_id"),
            "destination_type":
            obj_content.get("destination_type"),
            "destination_id":
            obj_content.get("destination_id")
        } for (obj_id, obj_content) in object_ids_with_jsons],
    )
Exemple #32
0
def log_event(session, obj=None, current_user_id=None, flush=True,
              force_obj=False, event=None):
  """Logs an event on object `obj`.

  Args:
    session: Current SQLAlchemy session (db.session)
    obj: object on which some operation took place
    current_user_id: ID of the user performing operation
    flush: If set to true, flush the session at the start
    force_obj: Used in case of custom attribute changes to force revision write
    event: event object to log
  Returns:
    Uncommitted models.Event instance
  """
  if flush:
    session.flush()
  if current_user_id is None:
    current_user_id = get_current_user_id()
  revisions = _get_log_revisions(current_user_id, obj=obj, force_obj=force_obj)
  if obj is None:
    resource_id = 0
    resource_type = None
    action = "BULK"
    context_id = 0
  else:
    resource_id = obj.id
    resource_type = str(obj.__class__.__name__)
    try:
      action = request.method
    except RuntimeError as exp:
      # Exception should affect the import request.
      action = "BULK"
      logger.warning("Request retrieval has failed: %s", exp.message)

    context_id = obj.context_id
  if not revisions:
    return event
  if event is None:
    event = Event(
        modified_by_id=current_user_id,
        action=action,
        resource_id=resource_id,
        resource_type=resource_type,
        context_id=context_id)
    session.add(event)
  event.revisions.extend(revisions)
  return event
  def bulk_update(cls, src):
    """Update statuses for bunch of tasks in a bulk.

    Args:
        src: input json with next structure:
          [{"status": "Assigned", "id": 1}, {"status": "In Progress", "id": 2}]

    Returns:
        list of updated_instances
    """
    new_prv_state_map = {
        cls.DEPRECATED: (cls.ASSIGNED, cls.IN_PROGRESS, cls.FINISHED,
                         cls.VERIFIED, cls.DECLINED),
        cls.IN_PROGRESS: (cls.ASSIGNED, ),
        cls.FINISHED: (cls.IN_PROGRESS, cls.DECLINED),
        cls.VERIFIED: (cls.FINISHED, ),
        cls.DECLINED: (cls.FINISHED, ),
        cls.ASSIGNED: (),
    }
    uniq_states = set([item['state'] for item in src])
    if len(list(uniq_states)) != 1:
      raise BadRequest("Request's JSON contains multiple statuses for "
                       "CycleTasks")
    new_state = uniq_states.pop()
    LOGGER.info("Do bulk update CycleTasks with '%s' status", new_state)
    if new_state not in cls.VALID_STATES:
      raise BadRequest("Request's JSON contains invalid statuses for "
                       "CycleTasks")
    prv_states = new_prv_state_map[new_state]
    all_ids = {item['id'] for item in src}
    # Eagerly loading is needed to get user permissions for CycleTask faster
    updatable_objects = cls.eager_query().filter(
        cls.id.in_(list(all_ids)),
        cls.status.in_(prv_states))
    if new_state in (cls.VERIFIED, cls.DECLINED):
      updatable_objects = [obj for obj in updatable_objects
                           if obj.cycle.is_verification_needed]
    # Bulk update works only on MyTasks page. Don't need to check for
    # WorkflowMembers' permissions here. User should update only his own tasks.
    updatable_objects = [obj for obj in updatable_objects
                         if obj.current_user_wfa_or_assignee()]
    # Queries count is constant because we are using eager query for objects.
    for obj in updatable_objects:
      obj.status = new_state
      obj.modified_by_id = login.get_current_user_id()
    return updatable_objects
Exemple #34
0
 def do_update_attr(cls, obj, json_obj, attr):
   """Perform the update to ``obj`` required to make the attribute attr
   equivalent in ``obj`` and ``json_obj``.
   """
   if (hasattr(attr, '__call__')):
     # The attribute has been decorated with a callable, grab the name and
     # invoke the callable to get the value
     attr_name = attr.attr_name
     value = attr(cls, obj, json_obj)
   else:
     # Lookup the method to use to perform the update. Use reflection to
     # key off of the type of the attribute and invoke the method of the
     # same name.
     attr_name = attr
     class_attr = getattr(obj.__class__, attr_name)
     method = getattr(cls, class_attr.__class__.__name__)
     value = method(obj, json_obj, attr_name, class_attr)
   if isinstance(value, (set, list)):
     # SQLAlchemy instrumentation botches up if we replace entire collections
     # It works if we update them with changes
     new_set = set(value)
     old_set = set(getattr(obj, attr_name))
     coll_class_attr = getattr(obj.__class__, attr_name)
     coll_attr = getattr(obj, attr_name)
     # Join table objects require special handling so that we can be sure to
     # set the modified_by_id correctly
     if isinstance(coll_class_attr, AssociationProxy):
       current_user_id = get_current_user_id()
       proxied_attr = coll_class_attr.local_attr
       proxied_property = coll_class_attr.remote_attr
       proxied_set_map = dict([(getattr(i, proxied_property.key), i)\
           for i in getattr(obj, proxied_attr.key)])
       coll_attr = getattr(obj, proxied_attr.key)
       for item in new_set - old_set:
         new_item = coll_class_attr.creator(item)
         new_item.modified_by_id = current_user_id
         coll_attr.append(new_item)
       for item in old_set - new_set:
         coll_attr.remove(proxied_set_map[item])
     else:
       for item in new_set - old_set:
         coll_attr.append(item)
       for item in old_set - new_set:
         coll_attr.remove(item)
   else:
     setattr(obj, attr_name, value)
  def bulk_update(cls, src):
    """Update statuses for bunch of tasks in a bulk.

    Args:
        src: input json with next structure:
          [{"status": "Assigned", "id": 1}, {"status": "In Progress", "id": 2}]

    Returns:
        list of updated_instances
    """
    new_prv_state_map = {
        cls.DEPRECATED: (cls.ASSIGNED, cls.IN_PROGRESS, cls.FINISHED,
                         cls.VERIFIED, cls.DECLINED),
        cls.IN_PROGRESS: (cls.ASSIGNED, ),
        cls.FINISHED: (cls.IN_PROGRESS, cls.DECLINED),
        cls.VERIFIED: (cls.FINISHED, ),
        cls.DECLINED: (cls.FINISHED, ),
        cls.ASSIGNED: (),
    }
    uniq_states = set([item['state'] for item in src])
    if len(list(uniq_states)) != 1:
      raise BadRequest("Request's JSON contains multiple statuses for "
                       "CycleTasks")
    new_state = uniq_states.pop()
    LOGGER.info("Do bulk update CycleTasks with '%s' status", new_state)
    if new_state not in cls.VALID_STATES:
      raise BadRequest("Request's JSON contains invalid statuses for "
                       "CycleTasks")
    prv_states = new_prv_state_map[new_state]
    all_ids = {item['id'] for item in src}
    # Eagerly loading is needed to get user permissions for CycleTask faster
    updatable_objects = cls.eager_query().filter(
        cls.id.in_(list(all_ids)),
        cls.status.in_(prv_states))
    if new_state in (cls.VERIFIED, cls.DECLINED):
      updatable_objects = [obj for obj in updatable_objects
                           if obj.cycle.is_verification_needed]
    # Bulk update works only on MyTasks page. Don't need to check for
    # WorkflowMembers' permissions here. User should update only his own tasks.
    updatable_objects = [obj for obj in updatable_objects
                         if obj.current_user_wfa_or_assignee()]
    # Queries count is constant because we are using eager query for objects.
    for obj in updatable_objects:
      obj.status = new_state
      obj.modified_by_id = login.get_current_user_id()
    return updatable_objects
Exemple #36
0
def add_notification(obj, notif_type_name):
  """Add notification for object uses notif_type_cache as cache"""
  from ggrc.models import all_models
  notif_type_id = all_models.NotificationType.query.filter_by(
      name=notif_type_name).one().id

  # I don't like to have flush here, but we need a ID for newly created objects
  if not obj.id:
    db.session.flush()

  db.session.add(all_models.Notification(
      object=obj,
      send_on=datetime.datetime.utcnow(),
      notification_type_id=notif_type_id,
      runner=all_models.Notification.RUNNER_FAST,
      modified_by_id=get_current_user_id()
  ))
Exemple #37
0
  def add_comment(comment_text, source, initiator_object=None):
    """Adds comment into the session.

      Args:
        comment_text: comment text.
        source: object to which comment will be attached via relationship.
        initiator_object: initiator of comment creation.
    """
    created_comment = comment.Comment(
        description=comment_text,
        modified_by_id=login.get_current_user_id(),
        initiator_instance=initiator_object,
    )
    relationship.Relationship(
        source=source,
        destination=created_comment
    )
Exemple #38
0
def _relate_assignees(
        assessment,  # type: models.Assessment
        snapshot,  # type: models.Snapshot
        snapshot_rev_content,  # type: Dict[str, Any]
        template,  # type: models.AssessmentTemplate
        audit  # type: models.Audit
):
    # type: (...) -> None
    """Relate assignees from audit, snapshot, and template to assessments.

  Relate people assigned to audit, snapshot and template to assessment. People
  will be taken from specific roles on audit and snapshot or directly from the
  template according to template settings.

  Args:
    assessment (models.Assessment): Assessment model instance.
    snapshot (models.Snapshot): Snapshot model instance used during assessment
      generation.
    snapshot_rev_content (dict): Dict with content of snapshot's revision. It
      is passed here directly instead of getting it from snapshot it is better
      for performance to compute it one time and pass it everywhere.
    template (models.AssessmentTempalte): AssessmentTemplate instance used
      during assessment generation.
    audit (models.Audit): Audit instance the assessment is generated for.

  Returns:
    None.
  """
    if template is not None:
        template_settings = template.default_people
    else:
        template_settings = {
            "assignees": "Principal Assignees",
            "verifiers": "Auditors",
        }

    role_people_map = _generate_role_people_map(audit, snapshot,
                                                snapshot_rev_content)
    assignee_ids = _get_people_ids_by_role("assignees", "Audit Lead",
                                           template_settings, role_people_map)
    verifier_ids = _get_people_ids_by_role("verifiers", "Auditors",
                                           template_settings, role_people_map)

    _generate_assignee_relations(assessment, assignee_ids, verifier_ids,
                                 [get_current_user_id()])
def _propagate_to_wf_children(new_wf_acls, child_class):
    """Propagate newly added roles to workflow objects.

  Args:
    wf_new_acl: list of all newly created acl entries for workflows

  Returns:
    list of newly created acl entries for task groups.
  """

    child_table = child_class.__table__
    acl_table = all_models.AccessControlList.__table__
    acr_table = all_models.AccessControlRole.__table__.alias("parent_acr")
    acr_mapped_table = all_models.AccessControlRole.__table__.alias("mapped")

    current_user_id = login.get_current_user_id()

    select_statement = sa.select([
        acl_table.c.person_id,
        acr_mapped_table.c.id,
        child_table.c.id,
        sa.literal(child_class.__name__),
        sa.func.now(),
        sa.literal(current_user_id),
        sa.func.now(),
        acl_table.c.id.label("parent_id"),
        acl_table.c.id.label("parent_id_nn"),
    ]).select_from(
        sa.join(
            sa.join(
                sa.join(
                    child_table, acl_table,
                    sa.and_(
                        acl_table.c.object_id == child_table.c.workflow_id,
                        acl_table.c.object_type ==
                        all_models.Workflow.__name__,
                    )),
                acr_table,
            ), acr_mapped_table, acr_mapped_table.c.name == sa.func.concat(
                acr_table.c.name,
                " Mapped"))).where(acl_table.c.id.in_(new_wf_acls))

    _insert_select_acls(select_statement)

    return _get_child_ids(new_wf_acls, child_class)
Exemple #40
0
def propagate(full_propagate=False):
    """Propagate all ACLs caused by objects in new_objects list.

  Args:
    new_acl_ids: list of newly created ACL ids,
    new_relationship_ids: list of newly created relationship ids,
  """
    if not (hasattr(flask.g, "new_acl_ids")
            and hasattr(flask.g, "new_relationship_ids")
            and hasattr(flask.g, "deleted_objects")):
        return

    if flask.g.deleted_objects:
        with utils.benchmark(
                "Delete internal ACL entries for deleted objects"):
            _delete_orphan_acl_entries(flask.g.deleted_objects)

    _set_empty_base_ids()

    current_user_id = login.get_current_user_id()

    # The order of propagation of relationships and other ACLs is important
    # because relationship code excludes other ACLs from propagating.
    if flask.g.new_relationship_ids:
        with utils.benchmark("Propagate ACLs for new relationships"):
            _propagate_relationships(
                flask.g.new_relationship_ids,
                flask.g.new_acl_ids,
                current_user_id,
            )
    if flask.g.new_acl_ids:
        with utils.benchmark("Propagate new ACL entries"):
            _propagate(flask.g.new_acl_ids, current_user_id)

    # clear permissions memcache
    if not full_propagate and flask.g.user_ids:
        with utils.benchmark("Clear ACL memcache for specific users: %s" %
                             flask.g.user_ids):
            clear_users_permission_cache(flask.g.user_ids)

    del flask.g.new_acl_ids
    del flask.g.new_relationship_ids
    del flask.g.user_ids
    del flask.g.deleted_objects
Exemple #41
0
  def log_issues(self, issue_objs, action='modified'):
    """Create log information about issues such as event and revisions.

    Args:
        issue_objs: [(obj_type, obj_id)] List with types and ids of objects.
        action: action that will be displayed in revisions
    """
    current_user_id = login.get_current_user_id()
    event_id_query = all_models.Event.__table__.insert().values(
        modified_by_id=current_user_id,
        action='BULK',
        resource_id=0,
        resource_type=None,
    )
    try:
      event_id = db.session.execute(event_id_query).inserted_primary_key[0]
      self.create_revisions(issue_objs, event_id, current_user_id, action)
    except sa.exc.OperationalError as error:
      logger.exception(error)
Exemple #42
0
def log_event(session,
              obj=None,
              current_user_id=None,
              flush=True,
              force_obj=False):
    """Logs an event on object `obj`.

  Args:
    session: Current SQLAlchemy session (db.session)
    obj: object on which some operation took place
    current_user_id: ID of the user performing operation
    flush: If set to true, flush the session at the start
    force_obj: Used in case of custom attribute changes to force revision write
  Returns:
    Uncommitted models.Event instance
  """
    event = None
    if flush:
        session.flush()
    if current_user_id is None:
        current_user_id = get_current_user_id()
    revisions = _get_log_revisions(current_user_id,
                                   obj=obj,
                                   force_obj=force_obj)
    if obj is None:
        resource_id = 0
        resource_type = None
        action = 'BULK'
        context_id = 0
    else:
        resource_id = obj.id
        resource_type = str(obj.__class__.__name__)
        action = request.method
        context_id = obj.context_id
    if revisions:
        event = Event(modified_by_id=current_user_id,
                      action=action,
                      resource_id=resource_id,
                      resource_type=resource_type,
                      context_id=context_id)
        event.revisions = revisions
        session.add(event)
    return event
Exemple #43
0
    def _copy_snapshot_relationships(self):
        """Add relationships between snapshotted objects.

    Create relationships between individual snapshots if a relationship exists
    between a pair of object that was snapshotted. These relationships get
    created for all objects inside a single parent scope.
    """
        for parent in self.parents:
            query = """
          INSERT IGNORE INTO relationships (
              modified_by_id,
              created_at,
              updated_at,
              source_id,
              source_type,
              destination_id,
              destination_type,
              context_id
          )
          SELECT
              :user_id,
              now(),
              now(),
              snap_1.id,
              "Snapshot",
              snap_2.id,
              "Snapshot",
              snap_2.context_id
          FROM relationships AS rel
          INNER JOIN snapshots AS snap_1
              ON (snap_1.child_type, snap_1.child_id) =
                 (rel.source_type, rel.source_id)
          INNER JOIN snapshots AS snap_2
              ON (snap_2.child_type, snap_2.child_id) =
                 (rel.destination_type, rel.destination_id)
          WHERE
              snap_1.parent_id = :parent_id AND
              snap_2.parent_id = :parent_id
          """
            db.session.execute(query, {
                "user_id": get_current_user_id(),
                "parent_id": parent.id
            })
Exemple #44
0
def add_comment_about(proposal, reason, txt):
    """Create comment about proposal for reason with required text."""
    if not isinstance(proposal.instance, comment.Commentable):
        return
    txt = txt or ""
    txt = txt.strip()
    if txt.startswith("<p>"):
        txt = txt[3:]
        if txt.endswith("</p>"):
            txt = txt[:-4]
    txt = txt.strip()
    comment_text = proposal.build_comment_text(reason, txt,
                                               proposal.proposed_by)
    created_comment = all_models.Comment(
        description=comment_text,
        modified_by_id=login.get_current_user_id(),
        initiator_instance=proposal)
    all_models.Relationship(source=proposal.instance,
                            destination=created_comment)
Exemple #45
0
def _propagate_to_children(new_tg_acls, child_class, id_name, parent_class):
  """Propagate new acls to objects related to task groups

  Args:
    new_tg_acls: list of ids of newly created acl entries for task groups

  Returns:
    list of ids for newy created task group task or task group object entries.
  """

  child_table = child_class.__table__
  acl_table = all_models.AccessControlList.__table__

  current_user_id = login.get_current_user_id()

  parent_id_filed = getattr(child_table.c, id_name)

  select_statement = sa.select([
      acl_table.c.person_id,
      acl_table.c.ac_role_id,
      child_table.c.id,
      sa.literal(child_class.__name__),
      sa.func.now(),
      sa.literal(current_user_id),
      sa.func.now(),
      acl_table.c.id.label("parent_id"),
      acl_table.c.id.label("parent_id_nn"),
  ]).select_from(
      sa.join(
          child_table,
          acl_table,
          sa.and_(
              acl_table.c.object_id == parent_id_filed,
              acl_table.c.object_type == parent_class.__name__,
          )
      )
  ).where(
      acl_table.c.id.in_(new_tg_acls),
  )

  acl_utils.insert_select_acls(select_statement)

  return _get_child_ids(new_tg_acls, child_class)
    def _create_audit_relationships(self):
        """Create relationships between snapshot objects and audits.

    Generally snapshots are related to audits by default, but we also duplicate
    this data in relationships table for ACL propagation.
    """

        relationships_table = all_models.Relationship.__table__
        snapshot_table = all_models.Snapshot.__table__
        inserter = relationships_table.insert().prefix_with("IGNORE")

        audit_ids = {parent.id for parent in self.parents}
        if not audit_ids:
            return

        old_ids = self._get_audit_relationships(audit_ids)

        select_statement = sa.select([
            sa.literal(get_current_user_id()),
            sa.func.now(),
            sa.func.now(),
            snapshot_table.c.parent_id,
            snapshot_table.c.parent_type,
            snapshot_table.c.id,
            sa.literal(all_models.Snapshot.__name__),
        ]).select_from(snapshot_table).where(
            snapshot_table.c.parent_id.in_(audit_ids))

        db.session.execute(
            inserter.from_select([
                relationships_table.c.modified_by_id,
                relationships_table.c.created_at,
                relationships_table.c.updated_at,
                relationships_table.c.source_id,
                relationships_table.c.source_type,
                relationships_table.c.destination_id,
                relationships_table.c.destination_type,
            ], select_statement))

        new_ids = self._get_audit_relationships(audit_ids)
        created_ids = new_ids.difference(old_ids)
        acl.add_relationships(created_ids)
Exemple #47
0
  def parse_item(self, has_title=False):
    """Parse document link lines.

    Returns:
      list of documents for all URLs and evidences.
    """
    documents = []
    user_id = get_current_user_id()
    for line in self.raw_value.splitlines():
      link, title = self._parse_line(line)
      if not (link and title):
        return []
      documents.append(models.Document(
          link=link,
          title=title,
          modified_by_id=user_id,
          context=self.row_converter.obj.context,
      ))

    return documents
def _rel_child(parent_acl_ids, source=True):
    """Get left side of relationships mappings through source."""
    rel_table = all_models.Relationship.__table__
    acl_table = all_models.AccessControlList.__table__
    parent_acr = all_models.AccessControlRole.__table__.alias(
        "parent_acr_{}".format(source))
    child_acr = all_models.AccessControlRole.__table__.alias(
        "child_acr_{}".format(source))

    if source:
        object_id = rel_table.c.destination_id
        object_type = rel_table.c.destination_type
    else:
        object_id = rel_table.c.source_id
        object_type = rel_table.c.source_type

    acl_link = sa.and_(
        acl_table.c.object_id == rel_table.c.id,
        acl_table.c.object_type == all_models.Relationship.__name__,
    )

    select_statement = sa.select([
        acl_table.c.person_id.label("person_id"),
        child_acr.c.id.label("ac_role_id"),
        object_id.label("object_id"),
        object_type.label("object_type"),
        sa.func.now().label("created_at"),
        sa.literal(login.get_current_user_id()).label("modified_by_id"),
        sa.func.now().label("updated_at"),
        acl_table.c.id.label("parent_id"),
        acl_table.c.id.label("parent_id_nn"),
    ]).select_from(
        sa.join(
            sa.join(sa.join(rel_table, acl_table, acl_link), parent_acr,
                    parent_acr.c.id == acl_table.c.ac_role_id), child_acr,
            child_acr.c.parent_id == parent_acr.c.id)).where(
                sa.and_(
                    acl_table.c.id.in_(parent_acl_ids),
                    child_acr.c.object_type == object_type,
                ))
    return select_statement
Exemple #49
0
  def _set_assertions(self, values):
    """Set control assertions.

    Args:
        values: List of `ControlAssertion` objects.
    """
    # pylint: disable=not-an-iterable
    proxied_set_map = dict([
        (a.category, a) for a in self.categorized_assertions
    ])
    # pylint: enable=not-an-iterable
    old_set, new_set = set(self.assertions), set(values)
    current_user_id = login.get_current_user_id()

    for assertion in new_set - old_set:
      new_assertion = self.assertions.creator(assertion)
      new_assertion.modified_by_id = current_user_id
      self.categorized_assertions.append(new_assertion)

    for assertion in old_set - new_set:
      self.categorized_assertions.remove(proxied_set_map[assertion])
Exemple #50
0
    def parse_item(self, has_title=False):
        """Parse document link lines.

    Returns:
      list of documents for all URLs and evidences.
    """
        new_links = set()
        duplicate_new_links = set()

        documents = []
        user_id = get_current_user_id()

        for line in self.raw_value.splitlines():
            link, title = self._parse_line(line)
            if not (link and title):
                continue

            if link in new_links:
                duplicate_new_links.add(link)
            else:
                new_links.add(link)
                documents.append(
                    models.Document(
                        link=link,
                        title=title,
                        modified_by_id=user_id,
                        context=self.row_converter.obj.context,
                        document_type=self.DOCUMENT_TYPE,
                    ))

        if duplicate_new_links:
            # NOTE: We rely on the fact that links in duplicate_new_links are all
            # instances of unicode (if that assumption breaks, unicode encode/decode
            # errors can occur for non-ascii link values)
            self.add_warning(errors.DUPLICATE_IN_MULTI_VALUE,
                             column_name=self.display_name,
                             duplicates=u", ".join(
                                 sorted(duplicate_new_links)))

        return documents
Exemple #51
0
    def handle_comment_post(sender, obj=None, src=None, service=None):
        """Save information on which user created the Comment object

    Args:
      sender: the class of the object that initiated the server request
      obj: the instance of `sender` that initiated the server request
      src: a dictionary containing the POST data sent with request
      service: the server-side API service that handled the request
    Returns:
      None
    """
        # pylint: disable=unused-argument

        creator_id = get_current_user_id()

        obj_owner = ObjectOwner(
            person_id=creator_id,
            ownable_id=obj.id,
            ownable_type=obj.type,
        )

        db.session.add(obj_owner)
Exemple #52
0
def relate_assignees(assessment, snapshot, template, audit):
    """Generates assignee list and relates them to Assessment objects

    Args:
        assessment (model instance): Assessment model
        snapshot (model instance): Snapshot,
        template (model instance): AssessmentTemplate model nullable,
        audit (model instance): Audit
  """
    if template:
        template_settings = template.default_people
    else:
        template_settings = {
            "assessors": "Principal Assignees",
            "verifiers": "Auditors"
        }
    acl_dict = generate_role_object_dict(snapshot, audit)
    assignee_ids = get_people_ids_based_on_role("assessors", "Audit Lead",
                                                template_settings, acl_dict)
    verifier_ids = get_people_ids_based_on_role("verifiers", "Auditors",
                                                template_settings, acl_dict)
    generate_assignee_relations(assessment, assignee_ids, verifier_ids,
                                [get_current_user_id()])
    def test_get_cycle_task_dict(self):
        """Tests get_cycle_task_dict functionality."""
        contract = factories.ContractFactory(title=u"Contract1")
        cycle_task = wf_factories.CycleTaskGroupObjectTaskFactory(
            title=u"task1")
        relationship = factories.RelationshipFactory(source=contract,
                                                     destination=cycle_task)
        db.session.delete(relationship)
        db.session.commit()

        relationship_revision = Revision(obj=relationship,
                                         modified_by_id=None,
                                         action="deleted",
                                         content="{}")
        contract_revision = Revision(obj=contract,
                                     modified_by_id=None,
                                     action="deleted",
                                     content='{"display_name": "Contract1"}')
        revisions = [relationship_revision, contract_revision]
        factories.EventFactory(modified_by_id=login.get_current_user_id(),
                               action="DELETE",
                               resource_id=relationship.id,
                               resource_type=relationship.type,
                               revisions=revisions)
        task_dict = get_cycle_task_dict(cycle_task)
        self.assertEqual(task_dict["related_objects"][0],
                         u"Contract1 [removed from task]")

        # Test if we handle the title of the object being empty
        contract = factories.ContractFactory(title=u"")
        cycle_task = wf_factories.CycleTaskGroupObjectTaskFactory(
            title=u"task1")
        factories.RelationshipFactory(source=contract, destination=cycle_task)

        task_dict = get_cycle_task_dict(cycle_task)
        self.assertEqual(task_dict["related_objects"][0], u"Untitled object")
Exemple #54
0
  def _task_count(self, id):
    """Return open task count and overdue flag for a given user."""
    # id name is used as a kw argument and can't be changed here
    # pylint: disable=invalid-name,redefined-builtin

    if id != login.get_current_user_id():
      raise Forbidden()
    with benchmark("Make response"):
      # query below ignores acr.read flag because this is done on a
      # non_editable role that has read rights:
      counts_query = db.session.execute(
          """
          SELECT
              overdue,
              sum(task_count)
          FROM (
              SELECT
                  ct.end_date < :today AS overdue,
                  count(ct.id) AS task_count
              FROM cycle_task_group_object_tasks AS ct
              JOIN cycles AS c ON
                  c.id = ct.cycle_id
              JOIN access_control_list AS acl
                  ON acl.object_id = ct.id
                  AND acl.object_type = "CycleTaskGroupObjectTask"
              JOIN access_control_roles as acr
                  ON acl.ac_role_id = acr.id
              WHERE
                  ct.status != "Verified" AND
                  c.is_verification_needed = 1 AND
                  c.is_current = 1 AND
                  acl.person_id = :person_id AND
                  acr.name IN ("Task Assignees", "Task Secondary Assignees")
              GROUP BY overdue

              UNION ALL

              SELECT
                  ct.end_date < :today AS overdue,
                  count(ct.id) AS task_count
              FROM cycle_task_group_object_tasks AS ct
              JOIN cycles AS c ON
                  c.id = ct.cycle_id
              JOIN access_control_list AS acl
                  ON acl.object_id = ct.id
                  AND acl.object_type = "CycleTaskGroupObjectTask"
              JOIN access_control_roles as acr
                  ON acl.ac_role_id = acr.id
              WHERE
                  ct.status != "Finished" AND
                  c.is_verification_needed = 0 AND
                  c.is_current = 1 AND
                  acl.person_id = :person_id AND
                  acr.name IN ("Task Assignees", "Task Secondary Assignees")
              GROUP BY overdue
          ) as temp
          GROUP BY overdue
          """,
          {
              # Using today instead of DATE(NOW()) for easier testing with
              # freeze gun.
              "today": datetime.date.today(),
              "person_id": id,
          }
      )
      counts = dict(counts_query.fetchall())
      response_object = {
          "open_task_count": int(sum(counts.values())),
          "has_overdue": bool(counts.get(1, 0)),
      }
      return self.json_success_response(response_object, )
 def current_user_wfa_or_assignee(self):
   """Current user is WF Admin, Assignee or Secondary Assignee for self."""
   wfa_ids = self.workflow.get_person_ids_for_rolename("Admin")
   ta_ids = self.get_person_ids_for_rolename("Task Assignees")
   tsa_ids = self.get_person_ids_for_rolename("Task Secondary Assignees")
   return login.get_current_user_id() in set().union(wfa_ids, ta_ids, tsa_ids)
Exemple #56
0
  def _get_assessments(self, model, object_type, object_id):
    """Get a list of assessments.

    Get a list of assessments with all their data from the db, according to the
    request GET parameters.
    """

    ids_query = model.get_similar_objects_query(object_id, "Assessment")
    order_by = self._get_order_by_parameter()
    limit = self._get_limit_parameters()

    if not permissions.has_system_wide_read():
      if not permissions.is_allowed_read(object_type, object_id, None):
        raise Forbidden()
      acl = models.all_models.AccessControlList
      acr = models.all_models.AccessControlRole
      ids_query = db.session.query(acl.object_id).join(acr).filter(
          acr.read == 1,
          acl.object_type == "Assessment",
          acl.person_id == get_current_user_id(),
          acl.object_id.in_(ids_query),
      )

    query = models.Assessment.query.options(
        orm.Load(models.Assessment).undefer_group(
            "Assessment_complete",
        ),
        orm.Load(models.Assessment).joinedload(
            "audit"
        ).undefer_group(
            "Audit_complete",
        ),
        orm.Load(models.Assessment).joinedload(
            "custom_attribute_definitions"
        ).undefer_group(
            "CustomAttributeDefinitons_complete",
        ),
        orm.Load(models.Assessment).joinedload(
            "custom_attribute_values"
        ).undefer_group(
            "CustomAttributeValues_complete",
        ),
    ).filter(
        models.Assessment.id.in_(ids_query)
    )
    if order_by:
      query = pagination.apply_order_by(
          models.Assessment,
          query,
          order_by,
          models.Assessment,
      )

    if limit:
      objs = pagination.apply_limit(query, limit).all()
      total = query.count()
    else:
      objs = query.all()
      total = len(objs)

    # note that using pagination.get_total_count here would return wrong counts
    # due to query being an eager query.

    return objs, total
Exemple #57
0
    def _create(self, for_create, event, revisions, _filter):
        """Create snapshots of parent objects neighhood and create revisions for
    snapshots.

    Args:
      event: A ggrc.models.Event instance
      revisions: A set of tuples of pairs with revisions to which it should
        either create or update a snapshot of that particular audit
      _filter: Callable that should return True if it should be updated
    Returns:
      OperationResponse
    """
        # pylint: disable=too-many-locals,too-many-statements
        with benchmark("Snapshot._create"):
            with benchmark("Snapshot._create init"):
                user_id = get_current_user_id()
                missed_keys = set()
                data_payload = list()
                revision_payload = list()
                relationship_payload = list()
                response_data = dict()

                if self.dry_run and event is None:
                    event_id = 0
                else:
                    event_id = event.id

            with benchmark("Snapshot._create.filter"):
                if _filter:
                    for_create = {elem for elem in for_create if _filter(elem)}

            with benchmark("Snapshot._create._get_revisions"):
                revision_id_cache = get_revisions(for_create, revisions)

            response_data["revisions"] = revision_id_cache

            with benchmark("Snapshot._create.create payload"):
                for pair in for_create:
                    if pair in revision_id_cache:
                        revision_id = revision_id_cache[pair]
                        context_id = self.context_cache[pair.parent]
                        data = create_snapshot_dict(pair, revision_id, user_id,
                                                    context_id)
                        data_payload += [data]
                    else:
                        missed_keys.add(pair)

            if missed_keys:
                logger.warning(
                    "Tried to create snapshots for the following objects but "
                    "found no revisions: %s", missed_keys)

            with benchmark("Snapshot._create.write to database"):
                self._execute(models.Snapshot.__table__.insert(), data_payload)

            with benchmark("Snapshot._create.retrieve inserted snapshots"):
                snapshots = get_snapshots(for_create)

            with benchmark("Snapshot._create.access control list"):
                acl_payload = get_acl_payload(snapshots)

            with benchmark("Snapshot._create.write acls to database"):
                self._execute(all_models.AccessControlList.__table__.insert(),
                              acl_payload)

            with benchmark(
                    "Snapshot._create.create parent object -> snapshot rels"):
                for snapshot in snapshots:
                    parent = Stub(snapshot.parent_type, snapshot.parent_id)
                    base = Stub(snapshot.child_type, snapshot.child_id)
                    relationship = create_relationship_dict(
                        parent, base, user_id, self.context_cache[parent])
                    relationship_payload += [relationship]

            with benchmark("Snapshot._create.write relationships to database"):
                self._execute(models.Relationship.__table__.insert(),
                              relationship_payload)

            with benchmark("Snapshot._create.get created relationships"):
                created_relationships = {
                    (rel["source_type"], rel["source_id"],
                     rel["destination_type"], rel["destination_id"])
                    for rel in relationship_payload
                }
                relationships = get_relationships(created_relationships)

            with benchmark("Snapshot._create.create revision payload"):
                with benchmark(
                        "Snapshot._create.create snapshots revision payload"):
                    for snapshot in snapshots:
                        parent = Stub(snapshot.parent_type, snapshot.parent_id)
                        context_id = self.context_cache[parent]
                        data = create_snapshot_revision_dict(
                            "created", event_id, snapshot, user_id, context_id)
                        revision_payload += [data]

                with benchmark("Snapshot._create.create rel revision payload"):
                    for relationship in relationships:
                        parent = Stub(relationship.source_type,
                                      relationship.source_id)
                        context_id = self.context_cache[parent]
                        data = create_relationship_revision_dict(
                            "created", event_id, relationship, user_id,
                            context_id)
                        revision_payload += [data]

            with benchmark("Snapshot._create.write revisions to database"):
                self._execute(models.Revision.__table__.insert(),
                              revision_payload)
            return OperationResponse("create", True, for_create, response_data)
Exemple #58
0
    def _update(self, for_update, event, revisions, _filter):
        """Update (or create) parent objects' snapshots and create revisions for
    them.

    Args:
      event: A ggrc.models.Event instance
      revisions: A set of tuples of pairs with revisions to which it should
        either create or update a snapshot of that particular audit
      _filter: Callable that should return True if it should be updated
    Returns:
      OperationResponse
    """
        # pylint: disable=too-many-locals
        with benchmark("Snapshot._update"):
            user_id = get_current_user_id()
            missed_keys = set()
            snapshot_cache = dict()
            modified_snapshot_keys = set()
            data_payload_update = list()
            revision_payload = list()
            response_data = dict()

            if self.dry_run and event is None:
                event_id = 0
            else:
                event_id = event.id

            with benchmark("Snapshot._update.filter"):
                if _filter:
                    for_update = {elem for elem in for_update if _filter(elem)}

            with benchmark("Snapshot._update.get existing snapshots"):
                existing_snapshots = db.session.query(
                    models.Snapshot.id,
                    models.Snapshot.revision_id,
                    models.Snapshot.parent_type,
                    models.Snapshot.parent_id,
                    models.Snapshot.child_type,
                    models.Snapshot.child_id,
                ).filter(
                    tuple_(models.Snapshot.parent_type,
                           models.Snapshot.parent_id,
                           models.Snapshot.child_type,
                           models.Snapshot.child_id).in_(
                               {pair.to_4tuple()
                                for pair in for_update}))

                for esnap in existing_snapshots:
                    sid, rev_id, pair_tuple = esnap[0], esnap[1], esnap[2:]
                    pair = Pair.from_4tuple(pair_tuple)
                    snapshot_cache[pair] = (sid, rev_id)

            with benchmark("Snapshot._update.retrieve latest revisions"):
                revision_id_cache = get_revisions(
                    for_update,
                    filters=[
                        models.Revision.action.in_(["created", "modified"])
                    ],
                    revisions=revisions)

            response_data["revisions"] = {
                "old":
                {pair: values[1]
                 for pair, values in snapshot_cache.items()},
                "new": revision_id_cache
            }

            with benchmark("Snapshot._update.build snapshot payload"):
                for key in for_update:
                    if key in revision_id_cache:
                        sid, rev_id = snapshot_cache[key]
                        latest_rev = revision_id_cache[key]
                        if rev_id != latest_rev:
                            modified_snapshot_keys.add(key)
                            data_payload_update += [{
                                "_id": sid,
                                "_revision_id": latest_rev,
                                "_modified_by_id": user_id
                            }]
                    else:
                        missed_keys.add(key)

            if missed_keys:
                logger.warning(
                    "Tried to update snapshots for the following objects but "
                    "found no revisions: %s", missed_keys)

            if not modified_snapshot_keys:
                return OperationResponse("update", True, set(), response_data)

            with benchmark("Snapshot._update.write snapshots to database"):
                update_sql = models.Snapshot.__table__.update().where(
                    models.Snapshot.id == bindparam("_id")).values(
                        revision_id=bindparam("_revision_id"),
                        modified_by_id=bindparam("_modified_by_id"))
                self._execute(update_sql, data_payload_update)

            with benchmark("Snapshot._update.retrieve inserted snapshots"):
                snapshots = get_snapshots(modified_snapshot_keys)

            with benchmark(
                    "Snapshot._update.create snapshots revision payload"):
                for snapshot in snapshots:
                    parent = Stub(snapshot.parent_type, snapshot.parent_id)
                    context_id = self.context_cache[parent]
                    data = create_snapshot_revision_dict(
                        "modified", event_id, snapshot, user_id, context_id)
                    revision_payload += [data]

            with benchmark("Insert Snapshot entries into Revision"):
                self._execute(models.Revision.__table__.insert(),
                              revision_payload)
            return OperationResponse("update", True, for_update, response_data)
Exemple #59
0
def create_related_roles(base_objects, related_objects):
    """Create mapped roles for related objects

  Args:
    base_objects(defaultdict(dict)): Objects which have Assignee role
    related_objects(defaultdict(set)): Objects related to assigned
  """
    if not base_objects or not related_objects:
        return

    acl_row = namedtuple(
        "acl_row", "person_id object_id object_type ac_role_id parent_id")
    acl_parent = namedtuple("acl_parent", "context parent")
    acl_data = {}
    for base_stub, related_stubs in related_objects.items():
        for related_stub in related_stubs:
            for acl in base_objects[base_stub]:
                acr_id = acl.ac_role.id if acl.ac_role else acl.ac_role_id
                mapped_acr_id = get_mapped_role(
                    base_stub.type,
                    get_custom_roles_for(base_stub.type)[acr_id],
                    related_stub.type)
                if not mapped_acr_id:
                    raise Exception("Mapped role wasn't found for role with "
                                    "id: {}".format(acl.ac_role_id))
                acl_data[acl_row(
                    acl.person_id or acl.person.id,
                    related_stub.id,
                    related_stub.type,
                    mapped_acr_id,
                    acl.id,
                )] = acl_parent(acl.context, acl)

    # Find existing acl instances in db
    existing_acls = set(
        db.session.query(
            all_models.AccessControlList.person_id,
            all_models.AccessControlList.object_id,
            all_models.AccessControlList.object_type,
            all_models.AccessControlList.ac_role_id,
            all_models.AccessControlList.parent_id,
        ).filter(
            sa.tuple_(
                all_models.AccessControlList.person_id,
                all_models.AccessControlList.object_id,
                all_models.AccessControlList.object_type,
                all_models.AccessControlList.ac_role_id,
                all_models.AccessControlList.parent_id,
            ).in_(acl_data.keys())).all())
    # Find existing acl instances in session
    session_acls = {(
        a.person_id,
        a.object_id,
        a.object_type,
        a.ac_role_id,
        a.parent.id if a.parent else a.parent_id,
    ): (a.person_id, a.object_id, a.object_type, a.ac_role_id, a.parent)
                    for a in db.session.new
                    if isinstance(a, all_models.AccessControlList)}
    existing_acls.update(session_acls.keys())

    current_user_id = login.get_current_user_id()
    # Create new acl instance only if it absent in db and session
    for acl in set(acl_data.keys()) - existing_acls:
        # In some cases parent_id will be None, but parent object is not empty.
        # that's why we should additionally compare parent objects
        if (acl.person_id, acl.object_id, acl.object_type, acl.ac_role_id,
                acl_data[acl].parent) not in session_acls.values():
            db.session.add(
                all_models.AccessControlList(
                    person_id=acl.person_id,
                    ac_role_id=acl.ac_role_id,
                    object_id=acl.object_id,
                    object_type=acl.object_type,
                    context=acl_data[acl].context,
                    modified_by_id=current_user_id,
                    parent=acl_data[acl].parent,
                ))
def _rel_parent(parent_acl_ids=None, relationship_ids=None, source=True):
    """Get left side of relationships mappings through source."""
    rel_table = all_models.Relationship.__table__
    acl_table = all_models.AccessControlList.__table__
    parent_acr = all_models.AccessControlRole.__table__.alias(
        "parent_acr_{}".format(source))
    child_acr = all_models.AccessControlRole.__table__.alias(
        "child_acr_{}".format(source))
    # The grandchild is only used to check the child part of the relationship. We
    # might want to check if it would be more efficient to store grandchild info
    # in the child ACR entry instead of making an extra join on our tables.
    grandchild_acr = all_models.AccessControlRole.__table__.alias(
        "grandchild_acr_{}".format(source))
    where_conditions = []
    if relationship_ids is not None:
        where_conditions.append(rel_table.c.id.in_(relationship_ids))
        if parent_acl_ids:
            where_conditions.append(~acl_table.c.id.in_(parent_acl_ids))
    elif parent_acl_ids is not None:
        where_conditions.append(acl_table.c.id.in_(parent_acl_ids))

    if source:
        parent_object_id = rel_table.c.source_id
        parent_object_type = rel_table.c.source_type
        grandchild_object_type = rel_table.c.destination_type
    else:
        parent_object_id = rel_table.c.destination_id
        parent_object_type = rel_table.c.destination_type
        grandchild_object_type = rel_table.c.source_type

    select_statement = sa.select([
        acl_table.c.person_id.label("person_id"),
        child_acr.c.id.label("ac_role_id"),
        rel_table.c.id.label("object_id"),
        sa.literal(all_models.Relationship.__name__).label("object_type"),
        sa.func.now().label("created_at"),
        sa.literal(login.get_current_user_id()).label("modified_by_id"),
        sa.func.now().label("updated_at"),
        acl_table.c.id.label("parent_id"),
        acl_table.c.id.label("parent_id_nn"),
    ]).select_from(
        sa.join(
            sa.join(
                sa.join(
                    sa.join(
                        rel_table, acl_table,
                        sa.and_(
                            acl_table.c.object_id == parent_object_id,
                            acl_table.c.object_type == parent_object_type,
                        )), parent_acr,
                    parent_acr.c.id == acl_table.c.ac_role_id),
                child_acr,
                sa.and_(
                    child_acr.c.parent_id == parent_acr.c.id,
                    child_acr.c.object_type ==
                    all_models.Relationship.__name__,
                ),
            ), grandchild_acr,
            sa.and_(
                grandchild_acr.c.parent_id == child_acr.c.id,
                grandchild_acr.c.object_type == grandchild_object_type,
            ))).where(sa.and_(*where_conditions))
    return select_statement