Esempio n. 1
0
    def serialize(
        self,
        obj: Integration,
        attrs: Mapping[str, Any],
        user: User,
        include_config: bool = True,
        **kwargs: Any,
    ) -> MutableMapping[str, JSONData]:
        data = super().serialize(obj, attrs, user)

        if not include_config:
            return data

        data.update({"configOrganization": []})

        try:
            install = obj.get_installation(
                organization_id=self.organization_id)
        except NotImplementedError:
            # The integration may not implement a Installed Integration object
            # representation.
            pass
        else:
            data.update(
                {"configOrganization": install.get_organization_config()})

            # Query param "action" only attached in TicketRuleForm modal.
            if self.params.get("action") == "create":
                data["createIssueConfig"] = install.get_create_issue_config(
                    None, user, params=self.params)

        return data
Esempio n. 2
0
    def serialize(
        self, obj: Integration, attrs: Mapping[str, Any], user: User, **kwargs: Any
    ) -> MutableMapping[str, JSONData]:
        data = super().serialize(obj, attrs, user)
        organization_id = kwargs.pop("organization_id")
        installation = obj.get_installation(organization_id)

        if self.action == "link":
            config = installation.get_link_issue_config(self.group, params=self.params)
            data["linkIssueConfig"] = config

        if self.action == "create":
            config = installation.get_create_issue_config(self.group, user, params=self.params)
            data["createIssueConfig"] = config

        return data
Esempio n. 3
0
def where_should_sync(
    integration: Integration,
    key: str,
    organization_id: int | None = None,
) -> Sequence[Organization]:
    """
    Given an integration, get the list of organizations where the sync type in
    `key` is enabled. If an optional `organization_id` is passed, then only
    check the integration for that organization.
    """
    kwargs = dict()
    if organization_id:
        kwargs["id"] = organization_id

    return [
        organization
        for organization in integration.organizations.filter(**kwargs)
        if features.has("organizations:integrations-issue-sync", organization)
        and integration.get_installation(organization.id).should_sync(key)
    ]
Esempio n. 4
0
    def handle_status_change(
        self,
        integration: Integration,
        external_issue_key: str,
        status_change: Optional[Mapping[str, str]],
        project: Optional[str],
    ) -> None:
        if status_change is None:
            return

        organization_ids = OrganizationIntegration.objects.filter(
            integration_id=integration.id).values_list("organization_id",
                                                       flat=True)

        for organization_id in organization_ids:
            installation = integration.get_installation(organization_id)
            data = {
                "new_state": status_change["newValue"],
                # old_state is None when the issue is New
                "old_state": status_change.get("oldValue"),
                "project": project,
            }

            installation.sync_status_inbound(external_issue_key, data)
Esempio n. 5
0
    def _handle(
        self,
        integration: Integration,
        event: Mapping[str, Any],
        organization: Organization,
        repo: Repository,
        host: str | None = None,
    ) -> None:
        authors = {}
        client = integration.get_installation(
            organization_id=organization.id).get_client()
        gh_username_cache: MutableMapping[str, str | None] = {}

        for commit in event["commits"]:
            if not commit["distinct"]:
                continue

            if self.should_ignore_commit(commit):
                continue

            author_email = commit["author"]["email"]
            if "@" not in author_email:
                author_email = f"{author_email[:65]}@localhost"
            # try to figure out who anonymous emails are
            elif self.is_anonymous_email(author_email):
                gh_username: str | None = commit["author"].get("username")
                # bot users don't have usernames
                if gh_username:
                    external_id = self.get_external_id(gh_username)
                    if gh_username in gh_username_cache:
                        author_email = gh_username_cache[
                            gh_username] or author_email
                    else:
                        try:
                            commit_author = CommitAuthor.objects.get(
                                external_id=external_id,
                                organization_id=organization.id)
                        except CommitAuthor.DoesNotExist:
                            commit_author = None

                        if commit_author is not None and not self.is_anonymous_email(
                                commit_author.email):
                            author_email = commit_author.email
                            gh_username_cache[gh_username] = author_email
                        else:
                            try:
                                gh_user = client.get_user(gh_username)
                            except ApiError as exc:
                                logger.exception(str(exc))
                            else:
                                # even if we can't find a user, set to none so we
                                # don't re-query
                                gh_username_cache[gh_username] = None
                                try:
                                    identity = Identity.objects.get(
                                        external_id=gh_user["id"],
                                        idp__type=self.provider,
                                        idp__external_id=self.
                                        get_idp_external_id(integration, host),
                                    )
                                except Identity.DoesNotExist:
                                    pass
                                else:
                                    author_email = identity.user.email
                                    gh_username_cache[
                                        gh_username] = author_email
                                    if commit_author is not None:
                                        try:
                                            with transaction.atomic():
                                                commit_author.update(
                                                    email=author_email,
                                                    external_id=external_id)
                                        except IntegrityError:
                                            pass

                        if commit_author is not None:
                            authors[author_email] = commit_author

            # TODO(dcramer): we need to deal with bad values here, but since
            # its optional, lets just throw it out for now
            if len(author_email) > 75:
                author = None
            elif author_email not in authors:
                authors[
                    author_email] = author = CommitAuthor.objects.get_or_create(
                        organization_id=organization.id,
                        email=author_email,
                        defaults={"name": commit["author"]["name"][:128]},
                    )[0]

                update_kwargs = {}

                if author.name != commit["author"]["name"][:128]:
                    update_kwargs["name"] = commit["author"]["name"][:128]

                gh_username = commit["author"].get("username")
                if gh_username:
                    external_id = self.get_external_id(gh_username)
                    if author.external_id != external_id and not self.is_anonymous_email(
                            author.email):
                        update_kwargs["external_id"] = external_id

                if update_kwargs:
                    try:
                        with transaction.atomic():
                            author.update(**update_kwargs)
                    except IntegrityError:
                        pass
            else:
                author = authors[author_email]

            try:
                with transaction.atomic():
                    c = Commit.objects.create(
                        repository_id=repo.id,
                        organization_id=organization.id,
                        key=commit["id"],
                        message=commit["message"],
                        author=author,
                        date_added=parse_date(commit["timestamp"]).astimezone(
                            timezone.utc),
                    )
                    for fname in commit["added"]:
                        CommitFileChange.objects.create(
                            organization_id=organization.id,
                            commit=c,
                            filename=fname,
                            type="A")
                    for fname in commit["removed"]:
                        CommitFileChange.objects.create(
                            organization_id=organization.id,
                            commit=c,
                            filename=fname,
                            type="D")
                    for fname in commit["modified"]:
                        CommitFileChange.objects.create(
                            organization_id=organization.id,
                            commit=c,
                            filename=fname,
                            type="M")
            except IntegrityError:
                pass