def copy(self, _other=None, **kwargs): """Create a partial copy of the current workflow. """ columns = [ 'title', 'description', 'notify_on_change', 'notify_custom_message', 'end_date', 'start_date', 'repeat_every', 'unit', 'is_verification_needed' ] if kwargs.get('clone_people', False): access_control_list = [{ "ac_role_id": acl.ac_role.id, "person": { "id": person.id } } for person, acl in self.access_control_list] else: role_id = { name: ind for (ind, name) in role.get_custom_roles_for(self.type).iteritems() }['Admin'] access_control_list = [{ "ac_role_id": role_id, "person": { "id": get_current_user().id } }] target = self.copy_into(_other, columns, access_control_list=access_control_list, **kwargs) return target
def test_old_comments(self): """Test if notifications will be sent for mix of old and new comments""" cur_user = all_models.Person.query.filter_by( email="*****@*****.**").first() assigee_role_id = { v: k for k, v in get_custom_roles_for("Assessment").items() }["Assignees"] with factories.single_commit(): assessment = factories.AssessmentFactory() factories.AccessControlListFactory(ac_role_id=assigee_role_id, person=cur_user, object=assessment) with freeze_time("2015-04-01 17:13:10"): self.generator.generate_comment(assessment, "", "some comment1", send_notification="true") self.generator.generate_comment(assessment, "", "some comment2", send_notification="true") response = self.client.get("/_notifications/show_pending") for comment in ["some comment1", "some comment2"]: self.assertIn( comment, response.data, "Information about comment '{}' absent in report".format( comment))
def generate_task_group_task(self, task_group=None, data=None): """Generate task group task over api.""" if data is None: data = {} if not task_group: _, task_group = self.generate_task_group() task_group = self._session_add(task_group) default_start = self.random_date() default_end = self.random_date(default_start, date.today()) obj_name = "task_group_task" cycle_task_role_id = { v: k for (k, v) in role.get_custom_roles_for("TaskGroupTask").iteritems() }['Task Assignees'] tgt = TaskGroupTask( task_group_id=task_group.id, context_id=task_group.context.id, title="tgt " + factories.random_str(), start_date=default_start, end_date=default_end, ) obj_dict = self.obj_to_dict(tgt, obj_name) if "access_control_list" not in data: wf_admin_id = Person.query.first().id data["access_control_list"] = [ acl_helper.get_acl_json(cycle_task_role_id, wf_admin_id) ] obj_dict[obj_name].update(data) return self.generate(TaskGroupTask, obj_name, obj_dict)
def handle_relationship_creation(session, flush_context): """Create relations for mapped objects.""" # pylint: disable=unused-argument base_objects = defaultdict(set) related_objects = defaultdict(set) snapshot_ids = {} for obj in session.new: if isinstance(obj, all_models.Relationship) and ( issubclass(type(obj.source), Assignable) or issubclass(type(obj.destination), Assignable)): assign_obj, other = obj.source, obj.destination if not issubclass(type(obj.source), Assignable): assign_obj, other = other, assign_obj for acl in assign_obj.access_control_list: acr_id = acl.ac_role.id if acl.ac_role else acl.ac_role_id ac_role = get_custom_roles_for(acl.object_type).get( acr_id, None) if ac_role in assign_obj.ASSIGNEE_TYPES: assign_stub = Stub(assign_obj.type, assign_obj.id) other_stub = Stub(other.type, other.id) base_objects[assign_stub].add(acl) related_objects[assign_stub].add(other_stub) if other.type == "Snapshot": snapshot_ids[other.id] = assign_stub if base_objects: if snapshot_ids: add_related_snapshots(snapshot_ids, related_objects) create_related_roles(base_objects, related_objects)
def test_assigned_task_delete(self, user_role, ac_role, can_delete): """ Test possibility to delete of assigned cycle task""" user = self.users[user_role] workflow_obj = self.activate_workflow_with_cycle(self.workflow_obj)[1] cycle_task = workflow_obj.cycles[0].cycle_task_group_object_tasks[0] role_map = { name: ind for (ind, name) in role.get_custom_roles_for(all_models.Workflow.__name__).iteritems() } put_params = {'access_control_list': [ acl_helper.get_acl_json(role_map[ac_role], user.id), acl_helper.get_acl_json(role_map["Admin"], self.users["admin"].id), ]} response = self.api.put(workflow_obj, put_params) self.assert200(response) self.api.set_user(user) res = self.api.delete(cycle_task) if can_delete: self.assert200(res) else: self.assert403(res)
def test_assigned_task_delete(self, user_role, ac_role, can_delete): """ Test possibility to delete of assigned cycle task""" user = self.users[user_role] workflow_obj = self.activate_workflow_with_cycle(self.workflow_obj)[1] cycle_task = workflow_obj.cycles[0].cycle_task_group_object_tasks[0] role_map = { name: ind for (ind, name) in role.get_custom_roles_for( all_models.Workflow.__name__).iteritems() } put_params = { 'access_control_list': [ acl_helper.get_acl_json(role_map[ac_role], user.id), acl_helper.get_acl_json(role_map["Admin"], self.users["admin"].id), ] } response = self.api.put(workflow_obj, put_params) self.assert200(response) self.api.set_user(user) res = self.api.delete(cycle_task) if can_delete: self.assert200(res) else: self.assert403(res)
def copy(self, _other=None, **kwargs): columns = ['title', 'description', 'task_group', 'start_date', 'end_date', 'access_control_list', 'modified_by', 'task_type', 'response_options'] if kwargs.get('clone_people', False): access_control_list = [ {"ac_role_id": acl.ac_role_id, "person": {"id": person.id}} for person, acl in self.access_control_list ] else: role_id = { v: k for (k, v) in role.get_custom_roles_for(self.type).iteritems() }['Task Assignees'] access_control_list = [ {"ac_role_id": role_id, "person": {"id": get_current_user().id}} ] kwargs['modified_by'] = get_current_user() return self.copy_into(_other, columns, access_control_list=access_control_list, **kwargs)
def create_assignees(cls, obj, persons): """Create assignees for object. This is used only during object creation because we cannot create assignees at that point yet. Args: obj: Assignable object. persons: [("(string) email", "Assignee roles"), ...] A list of people and their roles Returns: [(person, acr_role), ...] A list of persons with their roles. """ from ggrc.access_control.role import get_custom_roles_for ac_roles = { acr_name: acr_id for acr_id, acr_name in get_custom_roles_for(obj.type).items() } assignees = [] with factories.single_commit(): for person, roles in persons: person = factories.PersonFactory(email=person) for role in roles.split(","): factories.AccessControlListFactory( person=person, ac_role_id=ac_roles[role], object=obj ) assignees.append((person, role)) return assignees
def generate_workflow(self, data=None): """ create a workflow with dict data return: wf if it was created, or response otherwise """ if data is None: data = {} obj_name = "workflow" data = copy.deepcopy(data) tgs = data.pop("task_groups", []) wf_instance = Workflow(title="wf " + factories.random_str()) obj_dict = self.obj_to_dict(wf_instance, obj_name) wf_admin_role_id = { n: i for (i, n) in role.get_custom_roles_for(Workflow.__name__).iteritems() }['Admin'] if "access_control_list" not in data: wf_admin_id = Person.query.first().id data["access_control_list"] = [ acl_helper.get_acl_json(wf_admin_role_id, wf_admin_id)] obj_dict[obj_name].update(data) response, workflow = self.generate(Workflow, obj_name, obj_dict) for task_group in tgs: self.generate_task_group(workflow, task_group) return response, workflow
def generate_task_group_task(self, task_group=None, data=None): """Generate task group task over api.""" if data is None: data = {} if not task_group: _, task_group = self.generate_task_group() task_group = self._session_add(task_group) default_start = self.random_date() default_end = self.random_date(default_start, date.today()) obj_name = "task_group_task" cycle_task_role_id = { v: k for (k, v) in role.get_custom_roles_for("TaskGroupTask").iteritems() }['Task Assignees'] tgt = TaskGroupTask( task_group_id=task_group.id, context_id=task_group.context.id, title="tgt " + factories.random_str(), start_date=default_start, end_date=default_end, ) obj_dict = self.obj_to_dict(tgt, obj_name) if "access_control_list" not in data: wf_admin_id = Person.query.first().id data["access_control_list"] = [ acl_helper.get_acl_json(cycle_task_role_id, wf_admin_id)] obj_dict[obj_name].update(data) return self.generate(TaskGroupTask, obj_name, obj_dict)
def get_wf_propagated_role_ids(): """Getting propagated role ids.""" wf_roles = role.get_custom_roles_for(all_models.Workflow.__name__) return { id_ for id_, name in wf_roles.items() if name in WF_PROPAGATED_ROLES }
def _test_assessment_users(self, asmt, users): """ Test that all users have correct roles on specified Assessment""" verification_errors = "" ac_roles = { acr_name: acr_id for acr_id, acr_name in get_custom_roles_for(asmt.type).items() } for user_name, expected_types in users.items(): for role in expected_types: try: user = all_models.Person.query.filter_by( name=user_name).first() acl_len = all_models.AccessControlPerson.query.join( all_models.AccessControlList ).filter( all_models.AccessControlList.ac_role_id == ac_roles[role], all_models.AccessControlPerson.person_id == user.id, all_models.AccessControlList.object_id == asmt.id, all_models.AccessControlList.object_type == asmt.type, ).count() self.assertEqual( acl_len, 1, "User {} is not mapped to {}".format( user.email, asmt.slug)) except AssertionError as error: verification_errors += "\n\nChecks for Users-Assessment mapping "\ "failed for user '{}' with:\n{}".format(user_name, str(error)) self.assertEqual(verification_errors, "", verification_errors)
def _create_cycle_task(task_group_task, cycle, cycle_task_group, current_user): """Create a cycle task along with relations to other objects""" description = models.CycleTaskGroupObjectTask.default_description if \ task_group_task.object_approval else task_group_task.description workflow = cycle.workflow start_date = workflow.calc_next_adjusted_date(task_group_task.start_date) end_date = workflow.calc_next_adjusted_date(task_group_task.end_date) access_control_list = [] for role_id, role_name in role.get_custom_roles_for( models.CycleTaskGroupObjectTask.__name__).iteritems(): for person_id in task_group_task.get_person_ids_for_rolename(role_name): access_control_list.append( {"ac_role_id": role_id, "person": {"id": person_id}} ) cycle_task_group_object_task = models.CycleTaskGroupObjectTask( context=cycle.context, cycle=cycle, cycle_task_group=cycle_task_group, task_group_task=task_group_task, title=task_group_task.title, description=description, sort_index=task_group_task.sort_index, start_date=start_date, end_date=end_date, access_control_list=access_control_list, status=models.CycleTaskGroupObjectTask.ASSIGNED, modified_by=current_user, task_type=task_group_task.task_type, response_options=task_group_task.response_options, ) return cycle_task_group_object_task
def get_role_id_for_obj(obj, role_name): """Return role id for ent instance and role_name.""" from ggrc.access_control import role as ac_role for role_id, name in ac_role.get_custom_roles_for(obj.type).iteritems(): if name == role_name: return role_id return None
def init_workflow(self): """Creates a workflow which is owned by an user with Admin role""" admin_role_id = { n: i for (i, n) in role.get_custom_roles_for(Workflow.__name__).iteritems() }['Admin'] initial_workflow_data = { "title": "test workflow", "description": "test workflow", "access_control_list": [ acl_helper.get_acl_json(admin_role_id, self.users['admin'].id)], "status": "Draft", "task_groups": [{ "title": "task group 1", "contact": self.person_dict(self.users['admin'].id), "task_group_tasks": [{ "title": "task 1", "description": "some task", "contact": self.person_dict(self.users['admin'].id), "start_date": date(2016, 5, 26), "end_date": date(2016, 5, 28), }], "task_group_objects": self.random_objects[:2] }] } self.workflow_res, self.workflow_obj =\ self.generator.generate_workflow(initial_workflow_data)
def copy(self, _other=None, **kwargs): """Create a partial copy of the current workflow. """ columns = ['title', 'description', 'notify_on_change', 'notify_custom_message', 'end_date', 'start_date', 'repeat_every', 'unit', 'is_verification_needed'] if kwargs.get('clone_people', False): access_control_list = [{"ac_role": acl.ac_role, "person": acl.person} for acl in self.access_control_list] else: role_id = { name: ind for (ind, name) in role.get_custom_roles_for(self.type).iteritems() }['Admin'] access_control_list = [{"ac_role_id": role_id, "person": {"id": get_current_user().id}}] target = self.copy_into(_other, columns, access_control_list=access_control_list, **kwargs) return target
def test_old_comments(self): """Test if notifications will be sent for mix of old and new comments""" cur_user = all_models.Person.query.filter_by( email="*****@*****.**" ).first() assigee_role_id = { v: k for k, v in get_custom_roles_for("Assessment").items() }["Assignees"] with factories.single_commit(): assessment = factories.AssessmentFactory() factories.AccessControlListFactory( ac_role_id=assigee_role_id, person=cur_user, object=assessment ) with freeze_time("2015-04-01 17:13:10"): self.generator.generate_comment( assessment, "", "some comment1", send_notification="true" ) self.generator.generate_comment( assessment, "", "some comment2", send_notification="true" ) response = self.client.get("/_notifications/show_pending") for comment in ["some comment1", "some comment2"]: self.assertIn( comment, response.data, "Information about comment '{}' absent in report".format(comment) )
def _test_assessment_users(self, asmt, users): """ Test that all users have correct roles on specified Assessment""" verification_errors = "" ac_roles = { acr_name: acr_id for acr_id, acr_name in get_custom_roles_for(asmt.type).items() } for user_name, expected_types in users.items(): for role in expected_types: try: user = all_models.Person.query.filter_by(name=user_name).first() acl_len = all_models.AccessControlList.query.filter_by( ac_role_id=ac_roles[role], person_id=user.id, object_id=asmt.id, object_type=asmt.type, ).count() self.assertEqual( acl_len, 1, "User {} is not mapped to {}".format(user.email, asmt.slug) ) except AssertionError as error: verification_errors += "\n\nChecks for Users-Assessment mapping "\ "failed for user '{}' with:\n{}".format(user_name, str(error)) self.assertEqual(verification_errors, "", verification_errors)
def create_related_roles(context): """Create related roles for Workflow related objects. Args: context: dictionary with information for ACL propagation. """ if not context: return for related in context.values(): for rel_model, rel_acl_map in related.iteritems(): for rel_id, acl_set in rel_acl_map.iteritems(): for p_acl in acl_set: rel_person_id = p_acl.person.id if p_acl.person else p_acl.person_id custom_roles = get_custom_roles_for(p_acl.object_type) parent_acr_id = (p_acl.ac_role.id if p_acl.ac_role else p_acl.ac_role_id) parent_acr_name = custom_roles[parent_acr_id] rel_acr_name = "{} Mapped".format(parent_acr_name) rel_acr_id = next(ind for ind in custom_roles if custom_roles[ind] == rel_acr_name) db.session.add( all_models.AccessControlList( person_id=rel_person_id, ac_role_id=rel_acr_id, object_type=rel_model.__name__, object_id=rel_id, parent=p_acl, modified_by_id=login.get_current_user_id(), ))
def generate_workflow(self, data=None): """ create a workflow with dict data return: wf if it was created, or response otherwise """ if data is None: data = {} obj_name = "workflow" data = copy.deepcopy(data) tgs = data.pop("task_groups", []) wf_instance = Workflow(title="wf " + factories.random_str()) obj_dict = self.obj_to_dict(wf_instance, obj_name) wf_admin_role_id = { n: i for ( i, n) in role.get_custom_roles_for(Workflow.__name__).iteritems() }['Admin'] if "access_control_list" not in data: wf_admin_id = Person.query.first().id data["access_control_list"] = [ acl_helper.get_acl_json(wf_admin_role_id, wf_admin_id) ] obj_dict[obj_name].update(data) response, workflow = self.generate(Workflow, obj_name, obj_dict) for task_group in tgs: self.generate_task_group(workflow, task_group) return response, workflow
def assert_acr_exist(name, definition_type): """Validate that there is no ACR with provided name.""" model_name = get_inflector_model_name_dict()[definition_type] acrs = {i.lower() for i in acr.get_custom_roles_for(model_name).values()} if name.lower() in acrs: raise ValueError( errors.DUPLICATE_CUSTOM_ROLE.format(role_name=name) )
def get_persons_for_rolename(self, role_name): """Return list of persons that are valid for send role_name.""" for role_id, name in role.get_custom_roles_for(self.type).iteritems(): if name != role_name: continue return [i.person for i in self.access_control_list if i.ac_role_id == role_id] return []
def setUp(self): super(TestAssessmentBase, self).setUp() self.api = ggrc.api_helper.Api() self.assignee_roles = { role_name: role_id for role_id, role_name in get_custom_roles_for("Assessment").items() if role_name in ["Assignees", "Creators", "Verifiers"] }
def validate_title(self, key, value): """Validate CAD title/name uniqueness. Note: title field is used for storing CAD names. CAD names need to follow 4 uniqueness rules: 1) Names must not match any attribute name on any existing object. 2) Object level CAD names must not match any global CAD name. 3) Object level CAD names can clash, but not for the same Object instance. This means we can have two CAD with a name "my cad", with different attributable_id fields. 4) Names must not match any existing custom attribute role name Third rule is handled by the database with unique key uq_custom_attribute (`definition_type`,`definition_id`,`title`). This validator should check for name collisions for 1st and 2nd rule. This validator works, because definition_type is never changed. It only gets set when the cad is created and after that only title filed can change. This makes validation using both fields possible. Args: value: custom attribute definition name Returns: value if the name passes all uniqueness checks. """ if key == "title" and self.definition_type: name = value.lower() definition_type = self.definition_type elif key == "definition_type" and self.title: name = self.title.lower() definition_type = value.lower() else: return value if name in self._get_reserved_names(definition_type): raise ValueError(u"Attribute '{}' is reserved for this object type." .format(name)) if (self._get_global_cad_names(definition_type).get(name) is not None and self._get_global_cad_names(definition_type).get(name) != self.id): raise ValueError(u"Global custom attribute '{}' " u"already exists for this object type" .format(name)) model_name = self.inflector_model_name_dict[definition_type] acrs = {i.lower() for i in acr.get_custom_roles_for(model_name).values()} if name in acrs: raise ValueError(u"Custom Role with a name of '{}' " u"already existsfor this object type".format(name)) if definition_type == "assessment": self.validate_assessment_title(name) return value
def setUp(self): super(TestAssigneeRBAC, self).setUp() self.api = Api() self.set_up_people() self.assignee_roles = { role_name: role_id for role_id, role_name in get_custom_roles_for("Assessment").items() if role_name in ["Assignees", "Creators", "Verifiers"] }
def populate_acl(self): """Add access_control_list info for older revisions.""" roles_dict = role.get_custom_roles_for(self.resource_type) reverted_roles_dict = {n: i for i, n in roles_dict.iteritems()} access_control_list = self._content.get("access_control_list") or [] map_field_to_role = { "principal_assessor": reverted_roles_dict.get("Principal Assignees"), "secondary_assessor": reverted_roles_dict.get("Secondary Assignees"), "contact": reverted_roles_dict.get("Primary Contacts"), "secondary_contact": reverted_roles_dict.get("Secondary Contacts"), "owners": reverted_roles_dict.get("Admin"), } exists_roles = {i["ac_role_id"] for i in access_control_list} for field, role_id in map_field_to_role.items(): if role_id in exists_roles or role_id is None: continue if field not in self._content: continue field_content = self._content.get(field) or {} if not field_content: continue if not isinstance(field_content, list): field_content = [field_content] person_ids = {fc.get("id") for fc in field_content if fc.get("id")} for person_id in person_ids: access_control_list.append({ "display_name": roles_dict[role_id], "ac_role_id": role_id, "context_id": None, "created_at": None, "object_type": self.resource_type, "updated_at": None, "object_id": self.resource_id, "modified_by_id": None, "person_id": person_id, # Frontend require data in such format "person": { "id": person_id, "type": "Person", "href": "/api/people/{}".format(person_id) }, "modified_by": None, "id": None, }) acl_with_people = self._populate_acl_with_people(access_control_list) filtered_acl = self._filter_internal_acls(acl_with_people) result_acl = [ acl for acl in filtered_acl if acl["ac_role_id"] in roles_dict ] return { "access_control_list": result_acl, }
def test_models_comments(self, obj_factory, _): """Test setting notification entries for model comments. Check if the correct notification entries are created when a comment gets posted. """ if obj_factory in self.SCOPING_OBJECT_FACTORIES: recipient_types = [ "Admin", "Primary Contacts", "Secondary Contacts", "Assignee", "Compliance Contacts", "Verifier", "Product Managers", "Technical / Program Managers", "Technical Leads", "System Owners", "Legal Counsels" ] else: recipient_types = [ "Admin", "Primary Contacts", "Secondary Contacts" ] person = all_models.Person.query.first() person_email = person.email with factories.single_commit(): obj = obj_factory( recipients=",".join(recipient_types), send_by_default=False, ) ac_roles = get_custom_roles_for(obj.type) for acr_id, acr_name in ac_roles.items(): if acr_name in recipient_types: factories.AccessControlListFactory(ac_role_id=acr_id, object=obj, person=person) self.generator.generate_comment(obj, "", "some comment", send_notification="true") notifications, notif_data = common.get_daily_notifications() self.assertEqual(len(notifications), 1, "Missing comment notification entry.") recip_notifs = notif_data.get(person_email, {}) comment_notifs = recip_notifs.get("comment_created", {}) self.assertEqual(len(comment_notifs), 1) # Check if correct revisions count is created revisions = Revision.query.filter( Revision.resource_type == 'Notification', Revision.resource_id.in_([n.id for n in notifications])) self.assertEqual(revisions.count(), 1) self.client.get("/_notifications/send_daily_digest") notifications = self._get_notifications( notif_type="comment_created").all() self.assertEqual(len(notifications), 0, "Found a comment notification that was not sent.")
def get_person_ids_for_rolename(self, role_name): """Return list of persons that are valid for send role_name.""" for role_id, name in role.get_custom_roles_for(self.type).iteritems(): if name != role_name: continue # TODO: use ac_role_id as temporary solution until GGRC-3784 implemented return [i.person.id for i in self.access_control_list if (i.ac_role and i.ac_role.id == role_id) or (i.ac_role_id and i.ac_role_id == role_id)] return []
def setUp(self): super(TestAssigneeRBAC, self).setUp() self.api = Api() self.set_up_people() self.assignee_roles = { role_name: role_id for role_id, role_name in get_custom_roles_for( "Assessment").items() if role_name in ["Assignees", "Creators", "Verifiers"] }
def assert_assignees(self, role, response, *users): """Check if Assignee people in response are same with passed users""" acls = response.json["assessment"]["access_control_list"] asmnt_roles = get_custom_roles_for("Assessment") acl_people = all_models.Person.query.filter( all_models.Person.id.in_([ acl.get("person", {}).get("id") for acl in acls if asmnt_roles.get(acl.get("ac_role_id")) == role ])) self.assertEqual(list(users), [p.email for p in acl_people])
def assignee_roles(self): """Returns assignee roles. Returns: A dictionary with assignee role name and id. """ return { role_name: role_id for role_id, role_name in get_custom_roles_for( self.type).iteritems() if role_name in self.ASSIGNEE_TYPES }
def assert_assignees(self, role, response, *users): """Check if Assignee people in response are same with passed users""" acls = response.json["assessment"]["access_control_list"] asmnt_roles = get_custom_roles_for("Assessment") acl_people = all_models.Person.query.filter( all_models.Person.id.in_([ a.get("person", {}).get("id") for a in acls if asmnt_roles.get(a.get("ac_role_id")) == role ]) ) self.assertEqual(list(users), [p.email for p in acl_people])
def handle_comment_post(mapper, connection, target): """Save information on which user created the Comment object.""" # pylint: disable=unused-argument for role_id, role_name in role.get_custom_roles_for(target.type).items(): user = get_current_user() if role_name == "Admin" and not user.is_anonymous(): AccessControlList( ac_role_id=role_id, person=user, object=target, ) return
def handle_comment_post(mapper, connection, target): """Save information on which user created the Comment object.""" # pylint: disable=unused-argument for role_id, role_name in role.get_custom_roles_for( target.type).items(): user = get_current_user() if role_name == "Admin" and not user.is_anonymous(): AccessControlList( ac_role_id=role_id, person=user, object=target, ) return
def test_models_comments(self, obj_factory, _): """Test setting notification entries for model comments. Check if the correct notification entries are created when a comment gets posted. """ if obj_factory in self.SCOPING_OBJECT_FACTORIES: recipient_types = ["Admin", "Primary Contacts", "Secondary Contacts", "Product Managers", "Technical / Program Managers", "Technical Leads", "System Owners", "Legal Counsels"] else: recipient_types = ["Admin", "Primary Contacts", "Secondary Contacts"] person = all_models.Person.query.first() person_email = person.email with factories.single_commit(): obj = obj_factory( recipients=",".join(recipient_types), send_by_default=False, ) ac_roles = get_custom_roles_for(obj.type) for acr_id, acr_name in ac_roles.items(): if acr_name in recipient_types: factories.AccessControlListFactory( ac_role_id=acr_id, object=obj, person=person ) self.generator.generate_comment( obj, "", "some comment", send_notification="true") notifications, notif_data = common.get_daily_notifications() self.assertEqual(len(notifications), 1, "Missing comment notification entry.") recip_notifs = notif_data.get(person_email, {}) comment_notifs = recip_notifs.get("comment_created", {}) self.assertEqual(len(comment_notifs), 1) # Check if correct revisions count is created revisions = Revision.query.filter( Revision.resource_type == 'Notification', Revision.resource_id.in_([n.id for n in notifications]) ) self.assertEqual(revisions.count(), 1) self.client.get("/_notifications/send_daily_digest") notifications = self._get_notifications(notif_type="comment_created").all() self.assertEqual(len(notifications), 0, "Found a comment notification that was not sent.")
def handle_acl_creation(session): """Create relations for mapped objects.""" base_objects = defaultdict(set) for obj in session.new: if isinstance(obj, all_models.AccessControlList): acr_id = obj.ac_role.id if obj.ac_role else obj.ac_role_id acr_name = get_custom_roles_for(obj.object_type).get(acr_id) if acr_name in Assignable.ASSIGNEE_TYPES: base_objects[Stub(obj.object_type, obj.object_id)].add(obj) if base_objects: related_objects = related(base_objects.keys(), RelationshipsCache()) snapshot_ids = collect_snapshot_ids(related_objects) if snapshot_ids: add_related_snapshots(snapshot_ids, related_objects) create_related_roles(base_objects, related_objects)
def ensure_assignee_is_workflow_member(self): # pylint: disable=invalid-name """Add Workflow Member role to user without role in scope of Workflow.""" people_with_role_ids = ( self.workflow.get_person_ids_for_rolename("Admin") + self.workflow.get_person_ids_for_rolename("Workflow Member")) if self.contact.id in people_with_role_ids: return wf_member_role_id = next( ind for ind, name in role.get_custom_roles_for("Workflow").iteritems() if name == "Workflow Member") all_models.AccessControlList( person=self.contact, ac_role_id=wf_member_role_id, object=self.workflow, modified_by=get_current_user(), )
def generate_role_object_dict(snapshot, audit): """Generate roles dict for sent snapshot and audit. returns dict of roles with key as role name and list of people ids as values. """ acr_dict = role.get_custom_roles_for(snapshot.child_type) acl_dict = defaultdict(list) # populated content should have access_control_list for acl in snapshot.revision.content["access_control_list"]: acl_dict[acr_dict[acl["ac_role_id"]]].append(acl["person_id"]) # populate Access Control List by generated role from the related Audit acl_dict["Audit Lead"].append(audit.contact_id) acl_dict["Auditors"].extend([user_role.person_id for user_role in audit.context.user_roles if user_role.role.name == u"Auditor"]) return acl_dict
def init_globals(models): """Load all ACRs and CADs into memory from db""" with app.app_context(): with factories.single_commit(): for model in models: AC_ROLES[model] = { name: id for id, name in get_custom_roles_for(model).items() } CADS[model] = { CAD_PERSON_TYPE: factories.CustomAttributeDefinitionFactory( title=CAD_PERSON_TITLE, definition_type=utils.underscore_from_camelcase(model), attribute_type=CAD_PERSON_TYPE, ).id }
def get_mapped_role(object_type, acr_name, mapped_obj_type): """Get AC role that is mapped to provided one. Args: object_type(str): Type of object acr_name(str): Name of AC role mapped_obj_type(str): Type of mapped object Returns: Id of AC role with name '<Assignee type> Mapped' or '<Assignee type> Document Mapped' will be returned """ obj_roles = { role_name: role_id for role_id, role_name in get_custom_roles_for(object_type).items() } doc_part = " Document" if mapped_obj_type == "Document" else "" return obj_roles.get("{}{} Mapped".format(acr_name, doc_part))
def generate_role_object_dict(snapshot, audit): """Generate roles dict for sent snapshot and audit. returns dict of roles with key as role name and list of people ids as values. """ acr_dict = role.get_custom_roles_for(snapshot.child_type) acl_dict = defaultdict(list) # populated content should have access_control_list for acl in snapshot.revision.content["access_control_list"]: acl_dict[acr_dict[acl["ac_role_id"]]].append(acl["person_id"]) # populate Access Control List by generated role from the related Audit acl_dict["Audit Lead"].append(audit.contact_id) acl_dict["Auditors"].extend([ user_role.person_id for user_role in audit.context.user_roles if user_role.role.name == u"Auditor" ]) return acl_dict
def modify_assignee(self, obj, email, new_roles): """Modfiy assignee type. Args: obj: Object email: Person's email new_role: New roles for AssigneeType """ person = models.Person.query.filter_by(email=email).first() ac_roles = { acr_name: acr_id for acr_id, acr_name in get_custom_roles_for(obj.type).items() } self.api.modify_object(obj, { "access_control_list": [ acl_helper.get_acl_json(ac_roles[role], person.id) for role in new_roles ] })
def populated_content(self): """Property. Contains the revision content dict. Updated by required values, generated from saved content dict.""" roles_dict = role.get_custom_roles_for(self.resource_type) reverted_roles_dict = {n: i for i, n in roles_dict.iteritems()} access_control_list = self.content.get("access_control_list") or [] map_field_to_role = { "principal_assessor": reverted_roles_dict.get("Principal Assignees"), "secondary_assessor": reverted_roles_dict.get("Secondary Assignees"), "contact": reverted_roles_dict.get("Primary Contacts"), "secondary_contact": reverted_roles_dict.get("Secondary Contacts"), } exists_roles = {i["ac_role_id"] for i in access_control_list} for field, role_id in map_field_to_role.items(): if field not in self.content: continue if role_id in exists_roles or role_id is None: continue person_id = (self.content.get(field) or {}).get("id") if not person_id: continue access_control_list.append({ "display_name": roles_dict[role_id], "ac_role_id": role_id, "context_id": None, "created_at": None, "object_type": self.resource_type, "updated_at": None, "object_id": self.resource_id, "modified_by_id": None, "person_id": person_id, "modified_by": None, "id": None, }) content = self.content.copy() content["access_control_list"] = access_control_list return content
def _create_test_cases_data(self): """Create test cases data: for object generation, expected data for checks""" def person_dict(person_id): """Return person data""" return { "href": "/api/people/%d" % person_id, "id": person_id, "type": "Person" } wf_admin_role_id = { n: i for (i, n) in role.get_custom_roles_for(Workflow.__name__).iteritems() }['Admin'] self.workflow_active = { "title": "workflow active title", "description": "workflow active description", "access_control_list": [ acl_helper.get_acl_json(wf_admin_role_id, self.person_1.id)], "notify_on_change": False, } self.task_group_active = { "title": "task group active title", "contact": person_dict(self.person_1.id), } self.task_group_tasks_active = [{ "title": "task active title 1", "description": "task active description 1", "contact": person_dict(self.person_1.id), "start_date": "07/01/2016", "end_date": "07/06/2016", }, { "title": "task active title 2", "description": "task active description 2", "contact": person_dict(self.person_1.id), "start_date": "07/07/2016", "end_date": "07/12/2016", }, { "title": "task active title 3", "description": "task active description 3", "contact": person_dict(self.person_1.id), "start_date": "07/13/2016", "end_date": "07/18/2016", }, { "title": "task active title 4", "description": "task active description 4", "contact": person_dict(self.person_1.id), "start_date": "07/19/2016", "end_date": "07/24/2016", }, { "title": "task active title 5", "description": "task active description 5", "contact": person_dict(self.person_1.id), "start_date": "07/25/2016", "end_date": "07/30/2016", }] # Active cycle tasks which should be generated from previous structure # at the beginning of each test self.generated_cycle_tasks_active = { "CYCLETASK-1": { "title": self.task_group_tasks_active[0]["title"], "description": self.task_group_tasks_active[0]["description"], "start_date": "2016-07-01", "end_date": "2016-07-06", "finished_date": "None", "verified_date": "None", "status": "Assigned" }, "CYCLETASK-2": { "title": self.task_group_tasks_active[1]["title"], "description": self.task_group_tasks_active[1]["description"], "start_date": "2016-07-07", "end_date": "2016-07-12", "finished_date": "None", "verified_date": "None", "status": "Declined" }, "CYCLETASK-3": { "title": self.task_group_tasks_active[2]["title"], "description": self.task_group_tasks_active[2]["description"], "start_date": "2016-07-13", "end_date": "2016-07-18", "finished_date": "None", "verified_date": "None", "status": "In Progress" }, "CYCLETASK-4": { "title": self.task_group_tasks_active[3]["title"], "description": self.task_group_tasks_active[3]["description"], "start_date": "2016-07-19", "end_date": "2016-07-22", "finished_date": "2016-07-01", "verified_date": "None", "status": "Finished" }, "CYCLETASK-5": { "title": self.task_group_tasks_active[4]["title"], "description": self.task_group_tasks_active[4]["description"], "start_date": "2016-07-25", "end_date": "2016-07-29", "finished_date": "2016-07-01", "verified_date": "2016-07-01", "status": "Verified" } } self.workflow_historical = { "title": "workflow historical title", "description": "workflow historical description", "access_control_list": [ acl_helper.get_acl_json(wf_admin_role_id, self.person_1.id)], "notify_on_change": False, } self.task_group_historical = { "title": "task group historical title", "contact": person_dict(self.person_1.id), } self.task_group_tasks_historical = [{ "title": "task historical title 1", "description": "task historical description 1", "contact": person_dict(self.person_1.id), "start_date": "05/01/2014", "end_date": "05/06/2014", }, { "title": "task historical title 2", "description": "task historical description 2", "contact": person_dict(self.person_1.id), "start_date": "05/07/2014", "end_date": "05/12/2014", }, { "title": "task historical title 3", "description": "task historical description 3", "contact": person_dict(self.person_1.id), "start_date": "05/13/2014", "end_date": "05/18/2014", }, { "title": "task historical title 4", "description": "task historical description 4", "contact": person_dict(self.person_1.id), "start_date": "05/19/2014", "end_date": "05/24/2014", }, { "title": "task historical title 5", "description": "task historical description 5", "contact": person_dict(self.person_1.id), "start_date": "05/25/2014", "end_date": "05/30/2014", }, ] # Historical cycle tasks which should be generated from previous structure # at the beginning of each test. self.generated_cycle_tasks_historical = { "CYCLETASK-6": { "title": self.task_group_tasks_historical[0]["title"], "description": self.task_group_tasks_historical[0]["description"], "start_date": "2014-05-01", "end_date": "2014-05-06", "finished_date": "None", "verified_date": "None", "status": "Assigned" }, "CYCLETASK-7": { "title": self.task_group_tasks_historical[1]["title"], "description": self.task_group_tasks_historical[1]["description"], "start_date": "2014-05-07", "end_date": "2014-05-12", "finished_date": "None", "verified_date": "None", "status": "Declined" }, "CYCLETASK-8": { "title": self.task_group_tasks_historical[2]["title"], "description": self.task_group_tasks_historical[2]["description"], "start_date": "2014-05-13", "end_date": "2014-05-16", "finished_date": "None", "verified_date": "None", "status": "In Progress" }, "CYCLETASK-9": { "title": self.task_group_tasks_historical[3]["title"], "description": self.task_group_tasks_historical[3]["description"], "start_date": "2014-05-19", "end_date": "2014-05-23", "finished_date": "2014-05-01", "verified_date": "None", "status": "Finished" }, "CYCLETASK-10": { "title": self.task_group_tasks_historical[4]["title"], "description": self.task_group_tasks_historical[4]["description"], "start_date": "2014-05-23", "end_date": "2014-05-30", "finished_date": "2014-05-01", "verified_date": "2014-05-01", "status": "Verified" } } # Expected cycle tasks which should be created in correct cycle task update # case. It is needed for most tests. self.expected_cycle_task_correct = { "CYCLETASK-1": { "title": self.task_group_tasks_active[0]["title"] + " one", "description": self.task_group_tasks_active[0]["description"] + " one", "start_date": "2016-06-01", "end_date": "2016-06-06", "finished_date": "None", "verified_date": "None", "status": "Assigned" }, "CYCLETASK-2": { "title": self.task_group_tasks_active[1]["title"] + " two", "description": self.task_group_tasks_active[1]["description"] + " two", "start_date": "2016-06-07", "end_date": "2016-06-12", "finished_date": "None", "verified_date": "None", "status": "Declined" }, "CYCLETASK-3": { "title": self.task_group_tasks_active[2]["title"] + " three", "description": self.task_group_tasks_active[2]["description"] + " three", "start_date": "2016-06-13", "end_date": "2016-06-18", "finished_date": "None", "verified_date": "None", "status": "In Progress" }, "CYCLETASK-4": { "title": self.task_group_tasks_active[3]["title"] + " four", "description": self.task_group_tasks_active[3]["description"] + " four", "start_date": "2016-06-19", "end_date": "2016-06-24", "finished_date": "2016-07-19", "verified_date": "None", "status": "Finished" }, "CYCLETASK-5": { "title": self.task_group_tasks_active[4]["title"] + " five", "description": self.task_group_tasks_active[4]["description"] + " five", "start_date": "2016-06-25", "end_date": "2016-06-30", "finished_date": "2016-07-25", "verified_date": "2016-08-30", "status": "Verified" }, "CYCLETASK-6": { "title": self.task_group_tasks_historical[0]["title"] + " one", "description": self.task_group_tasks_historical[0]["description"] + " one", "start_date": "2014-04-01", "end_date": "2014-04-06", "finished_date": "None", "verified_date": "None", "status": "Assigned" }, "CYCLETASK-7": { "title": self.task_group_tasks_historical[1]["title"] + " two", "description": self.task_group_tasks_historical[1]["description"] + " two", "start_date": "2014-04-07", "end_date": "2014-04-12", "finished_date": "None", "verified_date": "None", "status": "Declined" }, "CYCLETASK-8": { "title": self.task_group_tasks_historical[2]["title"] + " three", "description": self.task_group_tasks_historical[2]["description"] + " three", "start_date": "2014-04-13", "end_date": "2014-04-18", "finished_date": "None", "verified_date": "None", "status": "In Progress" }, "CYCLETASK-9": { "title": self.task_group_tasks_historical[3]["title"] + " four", "description": self.task_group_tasks_historical[3]["description"] + " four", "start_date": "2014-04-19", "end_date": "2014-04-24", "finished_date": "2014-05-19", "verified_date": "None", "status": "Finished" }, "CYCLETASK-10": { "title": self.task_group_tasks_historical[4]["title"] + " five", "description": self.task_group_tasks_historical[4]["description"] + " five", "start_date": "2014-04-25", "end_date": "2014-04-30", "finished_date": "2014-05-25", "verified_date": "2014-06-30", "status": "Verified" } } # This is an error message which should be shown during # test_cycle_task_create_error test self.expected_create_error = { 'Cycle Task': { 'row_errors': {errors.CREATE_INSTANCE_ERROR.format(line=13)} } } # Below is expected date errors for test_cycle_task_date_error. They should # be shown during date validator's tests. self.expected_date_error = { 'Cycle Task': { 'row_errors': { errors.INVALID_START_END_DATES.format( line=3, start_date="Start Date", end_date="End Date", ), errors.INVALID_STATUS_DATE_CORRELATION.format( line=4, date="Actual Finish Date", deny_states=DENY_FINISHED_DATES_STATUSES_STR, ), errors.INVALID_STATUS_DATE_CORRELATION.format( line=6, date="Actual Verified Date", deny_states=DENY_VERIFIED_DATES_STATUSES_STR, ), errors.INVALID_START_END_DATES.format( line=7, start_date="Actual Finish Date", end_date="Actual Verified Date", ), errors.INVALID_START_END_DATES.format( line=8, start_date="Start Date", end_date="End Date", ), }, } } # Below is expected cycle-tasks data which should appear in test DB after # test_cycle_task_date_error run self.expected_cycle_task_date_error = dict() self.expected_cycle_task_date_error.update( self.generated_cycle_tasks_active) self.expected_cycle_task_date_error.update( self.generated_cycle_tasks_historical) self.expected_cycle_task_date_error["CYCLETASK-9"] = ( self.expected_cycle_task_correct["CYCLETASK-9"]) self.expected_cycle_task_date_error["CYCLETASK-10"] = ( self.expected_cycle_task_correct["CYCLETASK-10"]) # Expected error message which should be shown after # test_cycle_task_permission_error run self.expected_permission_error = { 'Cycle Task': { 'block_errors': {errors.PERMISSION_ERROR.format(line=2)} } }
def content(self): """Property. Contains the revision content dict. Updated by required values, generated from saved content dict.""" # pylint: disable=too-many-locals roles_dict = role.get_custom_roles_for(self.resource_type) reverted_roles_dict = {n: i for i, n in roles_dict.iteritems()} access_control_list = self._content.get("access_control_list") or [] map_field_to_role = { "principal_assessor": reverted_roles_dict.get("Principal Assignees"), "secondary_assessor": reverted_roles_dict.get("Secondary Assignees"), "contact": reverted_roles_dict.get("Primary Contacts"), "secondary_contact": reverted_roles_dict.get("Secondary Contacts"), "owners": reverted_roles_dict.get("Admin"), } exists_roles = {i["ac_role_id"] for i in access_control_list} for field, role_id in map_field_to_role.items(): if field not in self._content: continue if role_id in exists_roles or role_id is None: continue field_content = self._content.get(field) or {} if not field_content: continue if not isinstance(field_content, list): field_content = [field_content] person_ids = {fc.get("id") for fc in field_content if fc.get("id")} for person_id in person_ids: access_control_list.append({ "display_name": roles_dict[role_id], "ac_role_id": role_id, "context_id": None, "created_at": None, "object_type": self.resource_type, "updated_at": None, "object_id": self.resource_id, "modified_by_id": None, "person_id": person_id, # Frontend require data in such format "person": { "id": person_id, "type": "Person", "href": "/api/people/{}".format(person_id) }, "modified_by": None, "id": None, }) populated_content = self._content.copy() # Add person with id and type for old snapshots compatibility for acl in access_control_list: if "person" not in acl: acl["person"] = {"id": acl.get("person_id"), "type": "Person"} populated_content["access_control_list"] = access_control_list if 'url' in self._content: reference_url_list = [] for key in ('url', 'reference_url'): link = self._content[key] # link might exist, but can be an empty string - we treat those values # as non-existing (empty) reference URLs if not link: continue # if creation/modification date is not available, we estimate it by # using the corresponding information from the Revision itself created_at = (self._content.get("created_at") or self.created_at.isoformat()) updated_at = (self._content.get("updated_at") or self.updated_at.isoformat()) reference_url_list.append({ "display_name": link, "document_type": "REFERENCE_URL", "link": link, "title": link, "id": None, "created_at": created_at, "updated_at": updated_at, }) populated_content['reference_url'] = reference_url_list return populated_content