def handle_assign_to( self, integration: Integration, external_issue_key: str, assigned_to: Optional[Mapping[str, str]], ) -> None: if not assigned_to: return email: Optional[str] = None assign = False new_value = assigned_to.get("newValue") if new_value is not None: try: email = self.parse_email(new_value) except AttributeError as e: logger.info( "vsts.failed-to-parse-email-in-handle-assign-to", extra={ "error": str(e), "integration_id": integration.id, "assigned_to_values": assigned_to, "external_issue_key": external_issue_key, }, ) return # TODO(lb): return if cannot parse email? assign = True sync_group_assignee_inbound( integration=integration, email=email, external_issue_key=external_issue_key, assign=assign, )
def handle_assignee_change( integration: Integration, data: Mapping[str, Any], use_email_scope: bool = False, ) -> None: assignee_changed = any(item for item in data["changelog"]["items"] if item["field"] == "assignee") if not assignee_changed: return fields = data["issue"]["fields"] # If there is no assignee, assume it was unassigned. assignee = fields.get("assignee") issue_key = data["issue"]["key"] if assignee is None: sync_group_assignee_inbound(integration, None, issue_key, assign=False) return email = get_assignee_email(integration, assignee, use_email_scope) # TODO(steve) check display name if not email: logger.info( "missing-assignee-email", extra={ "issue_key": issue_key, "integration_id": integration.id }, ) return sync_group_assignee_inbound(integration, email, issue_key, assign=True)
def handle_assign_to( integration: Integration, external_issue_key: str | None, assigned_to: Mapping[str, str] | None, ) -> None: if not assigned_to: return email: str | None = None assign = False new_value = assigned_to.get("newValue") if new_value is not None: email = parse_email(new_value) if not email: logger.info( "vsts.failed-to-parse-email-in-handle-assign-to", extra={ "error": "parse_error", "integration_id": integration.id, "assigned_to_values": assigned_to, "external_issue_key": external_issue_key, }, ) return # TODO(mgaeta): return if cannot parse email? assign = True sync_group_assignee_inbound( integration=integration, email=email, external_issue_key=external_issue_key, assign=assign, )
def test_assignee_sync_inbound_assign(self): group = self.group user_no_access = self.create_user() user_w_access = self.user integration = Integration.objects.create(provider="example", external_id="123456") integration.add_organization(group.organization, user_no_access) OrganizationIntegration.objects.filter( integration_id=integration.id, organization_id=group.organization.id ).update( config={ "sync_comments": True, "sync_status_outbound": True, "sync_status_inbound": True, "sync_assignee_outbound": True, "sync_assignee_inbound": True, } ) external_issue = ExternalIssue.objects.create( organization_id=group.organization.id, integration_id=integration.id, key="APP-123" ) GroupLink.objects.create( group_id=group.id, project_id=group.project_id, linked_type=GroupLink.LinkedType.issue, linked_id=external_issue.id, relationship=GroupLink.Relationship.references, ) with self.feature("organizations:integrations-issue-sync"): # no permissions groups_updated = sync_group_assignee_inbound( integration, user_no_access.email, "APP-123" ) assert not groups_updated # w permissions groups_updated = sync_group_assignee_inbound( integration, user_w_access.email, "APP-123" ) assert groups_updated[0] == group assert GroupAssignee.objects.filter( project=group.project, group=group, user=user_w_access, team__isnull=True ).exists() # confirm capitalization doesn't affect syncing groups_updated = sync_group_assignee_inbound( integration, user_w_access.email.title(), "APP-123" ) assert groups_updated[0] == group assert GroupAssignee.objects.filter( project=group.project, group=group, user=user_w_access, team__isnull=True ).exists()
def handle_assignee_change(integration, data, use_email_scope=False): assignee_changed = any(item for item in data["changelog"]["items"] if item["field"] == "assignee") if not assignee_changed: return fields = data["issue"]["fields"] # if no assignee, assume it was unassigned assignee = fields.get("assignee") issue_key = data["issue"]["key"] if assignee is None: sync_group_assignee_inbound(integration, None, issue_key, assign=False) return email = assignee.get("emailAddress") # pull email from API if we can use it if not email and use_email_scope: account_id = assignee.get("accountId") client = JiraApiClient( integration.metadata["base_url"], JiraCloud(integration.metadata["shared_secret"]), verify_ssl=True, ) email = client.get_email(account_id) # TODO(steve) check display name if not email: logger.info( "missing-assignee-email", extra={ "issue_key": issue_key, "integration_id": integration.id }, ) return sync_group_assignee_inbound(integration, email, issue_key, assign=True)
def test_assignee_sync_inbound_deassign(self): group = self.group integration = Integration.objects.create(provider="example", external_id="123456") integration.add_organization(group.organization, self.user) OrganizationIntegration.objects.filter( integration_id=integration.id, organization_id=group.organization.id).update( config={ "sync_comments": True, "sync_status_outbound": True, "sync_status_inbound": True, "sync_assignee_outbound": True, "sync_assignee_inbound": True, }) external_issue = ExternalIssue.objects.create( organization_id=group.organization.id, integration_id=integration.id, key="APP-123") GroupLink.objects.create( group_id=group.id, project_id=group.project_id, linked_type=GroupLink.LinkedType.issue, linked_id=external_issue.id, relationship=GroupLink.Relationship.references, ) GroupAssignee.objects.assign(group, self.user) with self.feature("organizations:integrations-issue-sync"): groups_updated = sync_group_assignee_inbound(integration, self.user.email, "APP-123", assign=False) assert groups_updated[0] == group assert not GroupAssignee.objects.filter( project=group.project, group=group, user=self.user, team__isnull=True).exists()