Exemplo n.º 1
0
class ServiceHook(Model):
    __include_in_export__ = True

    guid = models.CharField(max_length=32, unique=True, null=True)
    # hooks may be bound to an api application, or simply registered by a user
    application = FlexibleForeignKey("sentry.ApiApplication", null=True)
    actor_id = BoundedPositiveIntegerField(db_index=True)
    project_id = BoundedPositiveIntegerField(db_index=True, null=True)
    organization_id = BoundedPositiveIntegerField(db_index=True, null=True)
    url = models.URLField(max_length=512)
    secret = EncryptedTextField(default=generate_secret)
    events = ArrayField(of=models.TextField)
    status = BoundedPositiveIntegerField(default=0,
                                         choices=ObjectStatus.as_choices(),
                                         db_index=True)
    version = BoundedPositiveIntegerField(default=0, choices=((0, "0"), ))
    date_added = models.DateTimeField(default=timezone.now)

    objects = BaseManager(cache_fields=("guid", ))

    class Meta:
        app_label = "sentry"
        db_table = "sentry_servicehook"

    __repr__ = sane_repr("guid", "project_id")

    @property
    def created_by_sentry_app(self):
        return self.application_id and self.sentry_app

    @property
    def sentry_app(self):
        try:
            return SentryApp.objects.get(application_id=self.application_id)
        except SentryApp.DoesNotExist:
            return

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.guid is None:
            self.guid = uuid4().hex

    def __str__(self):
        return str(self.guid)

    def build_signature(self, body):
        return hmac.new(key=self.secret.encode("utf-8"),
                        msg=body.encode("utf-8"),
                        digestmod=sha256).hexdigest()

    def get_audit_log_data(self):
        return {"url": self.url}

    def add_project(self, project):
        """
        Add a project to the service hook.

        """
        ServiceHookProject.objects.create(project_id=project.id,
                                          service_hook_id=self.id)
Exemplo n.º 2
0
class Repository(Model):
    __core__ = True

    organization_id = BoundedPositiveIntegerField(db_index=True)
    name = models.CharField(max_length=200)
    url = models.URLField(null=True)
    provider = models.CharField(max_length=64, null=True)
    external_id = models.CharField(max_length=64, null=True)
    config = JSONField(default=lambda: {})
    status = BoundedPositiveIntegerField(
        default=ObjectStatus.VISIBLE,
        choices=ObjectStatus.as_choices(),
        db_index=True,
    )
    date_added = models.DateTimeField(default=timezone.now)

    class Meta:
        app_label = 'sentry'
        db_table = 'sentry_repository'
        unique_together = (('organization_id', 'name'),
                           ('organization_id', 'provider', 'external_id'))

    __repr__ = sane_repr('organization_id', 'name', 'provider')

    def get_provider(self):
        from sentry.plugins import bindings
        provider_cls = bindings.get('repository.provider').get(self.provider)
        return provider_cls(self.provider)
Exemplo n.º 3
0
class Widget(Model):
    """
    A dashboard widget.
    """
    __core__ = True

    dashboard = FlexibleForeignKey('sentry.Dashboard')
    order = BoundedPositiveIntegerField()
    title = models.CharField(max_length=255)
    display_type = BoundedPositiveIntegerField(
        choices=WidgetDisplayTypes.as_choices())
    display_options = JSONField(default={})
    date_added = models.DateTimeField(default=timezone.now)
    status = BoundedPositiveIntegerField(
        default=ObjectStatus.VISIBLE,
        choices=ObjectStatus.as_choices(),
    )

    class Meta:
        app_label = 'sentry'
        db_table = 'sentry_widget'
        unique_together = (
            ('dashboard', 'order'),
            ('dashboard', 'title'),
        )

    __repr__ = sane_repr('dashboard', 'title')
Exemplo n.º 4
0
class Integration(Model):
    __core__ = False

    organizations = models.ManyToManyField(
        "sentry.Organization", related_name="integrations", through=OrganizationIntegration
    )
    projects = models.ManyToManyField(
        "sentry.Project", related_name="integrations", through=ProjectIntegration
    )
    provider = models.CharField(max_length=64)
    external_id = models.CharField(max_length=64)
    name = models.CharField(max_length=200)
    # metadata might be used to store things like credentials, but it should NOT
    # be used to store organization-specific information, as the Integration
    # instance is shared among multiple organizations
    metadata = EncryptedJsonField(default=dict)
    status = BoundedPositiveIntegerField(
        default=ObjectStatus.VISIBLE, choices=ObjectStatus.as_choices(), null=True
    )
    date_added = models.DateTimeField(default=timezone.now, null=True)

    class Meta:
        app_label = "sentry"
        db_table = "sentry_integration"
        unique_together = (("provider", "external_id"),)

    def get_provider(self):
        from sentry import integrations

        return integrations.get(self.provider)

    def get_installation(self, organization_id, **kwargs):
        return self.get_provider().get_installation(self, organization_id, **kwargs)

    def has_feature(self, feature):
        return feature in self.get_provider().features

    def add_organization(self, organization, user=None, default_auth_id=None):
        """
        Add an organization to this integration.

        Returns False if the OrganizationIntegration was not created
        """
        try:
            org_integration, created = OrganizationIntegration.objects.get_or_create(
                organization_id=organization.id,
                integration_id=self.id,
                defaults={"default_auth_id": default_auth_id, "config": {}},
            )
            if not created and default_auth_id:
                org_integration.update(default_auth_id=default_auth_id)
        except IntegrityError:
            return False
        else:
            integration_added.send_robust(
                integration=self, organization=organization, user=user, sender=self.__class__
            )

            return org_integration
Exemplo n.º 5
0
class ServiceHook(Model):
    __core__ = True

    guid = models.CharField(max_length=32, unique=True, null=True)
    # hooks may be bound to an api application, or simply registered by a user
    application = FlexibleForeignKey('sentry.ApiApplication', null=True)
    actor_id = BoundedPositiveIntegerField(db_index=True)
    project_id = BoundedPositiveIntegerField(db_index=True)
    organization_id = BoundedPositiveIntegerField(db_index=True, null=True)
    url = models.URLField(max_length=512)
    secret = EncryptedTextField(default=generate_secret)
    events = ArrayField(of=models.TextField)
    status = BoundedPositiveIntegerField(default=0,
                                         choices=ObjectStatus.as_choices(),
                                         db_index=True)
    version = BoundedPositiveIntegerField(default=0, choices=((0, '0'), ))
    date_added = models.DateTimeField(default=timezone.now)

    objects = BaseManager(cache_fields=('guid', ))

    class Meta:
        app_label = 'sentry'
        db_table = 'sentry_servicehook'

    __repr__ = sane_repr('guid', 'project_id')

    @property
    def created_by_sentry_app(self):
        return (self.application_id and self.sentry_app)

    @property
    def sentry_app(self):
        try:
            return SentryApp.objects.get(application_id=self.application_id)
        except SentryApp.DoesNotExist:
            return

    def __init__(self, *args, **kwargs):
        super(ServiceHook, self).__init__(*args, **kwargs)
        if self.guid is None:
            self.guid = uuid4().hex

    def __unicode__(self):
        return six.text_type(self.guid)

    def build_signature(self, body):
        return hmac.new(
            key=self.secret.encode('utf-8'),
            msg=body.encode('utf-8'),
            digestmod=sha256,
        ).hexdigest()

    def get_audit_log_data(self):
        return {'url': self.url}
Exemplo n.º 6
0
class Repository(Model):
    __core__ = True

    organization_id = BoundedPositiveIntegerField(db_index=True)
    name = models.CharField(max_length=200)
    url = models.URLField(null=True)
    provider = models.CharField(max_length=64, null=True)
    external_id = models.CharField(max_length=64, null=True)
    config = JSONField(default=lambda: {})
    status = BoundedPositiveIntegerField(
        default=ObjectStatus.VISIBLE,
        choices=ObjectStatus.as_choices(),
        db_index=True,
    )
    date_added = models.DateTimeField(default=timezone.now)
    integration_id = BoundedPositiveIntegerField(db_index=True, null=True)

    class Meta:
        app_label = 'sentry'
        db_table = 'sentry_repository'
        unique_together = (
            ('organization_id', 'name'), ('organization_id', 'provider', 'external_id')
        )

    __repr__ = sane_repr('organization_id', 'name', 'provider')

    def has_integration_provider(self):
        return self.provider and self.provider.startswith('integrations:')

    def get_provider(self):
        from sentry.plugins import bindings
        if self.has_integration_provider():
            provider_cls = bindings.get('integration-repository.provider').get(self.provider)
            return provider_cls(self.provider)

        provider_cls = bindings.get('repository.provider').get(self.provider)
        return provider_cls(self.provider)

    def generate_delete_fail_email(self, error_message):
        from sentry.utils.email import MessageBuilder

        new_context = {
            'repo': self,
            'error_message': error_message,
            'provider_name': self.get_provider().name,
        }

        return MessageBuilder(
            subject='Unable to Delete Repository Webhooks',
            context=new_context,
            template='sentry/emails/unable-to-delete-repo.txt',
            html_template='sentry/emails/unable-to-delete-repo.html',
        )
Exemplo n.º 7
0
class OrganizationIntegration(DefaultFieldsModel):
    __core__ = False

    organization = FlexibleForeignKey("sentry.Organization")
    integration = FlexibleForeignKey("sentry.Integration")
    config = EncryptedJsonField(default=dict)

    default_auth_id = BoundedPositiveIntegerField(db_index=True, null=True)
    status = BoundedPositiveIntegerField(default=ObjectStatus.VISIBLE,
                                         choices=ObjectStatus.as_choices())

    class Meta:
        app_label = "sentry"
        db_table = "sentry_organizationintegration"
        unique_together = (("organization", "integration"), )
Exemplo n.º 8
0
class OrganizationIntegration(DefaultFieldsModel):
    __include_in_export__ = False

    organization = FlexibleForeignKey("sentry.Organization")
    integration = FlexibleForeignKey("sentry.Integration")
    config = EncryptedJsonField(default=dict)

    default_auth_id = BoundedPositiveIntegerField(db_index=True, null=True)
    status = BoundedPositiveIntegerField(
        default=ObjectStatus.VISIBLE, choices=ObjectStatus.as_choices()
    )
    # After the grace period, we will mark the status as disabled.
    grace_period_end = models.DateTimeField(null=True, blank=True, db_index=True)

    class Meta:
        app_label = "sentry"
        db_table = "sentry_organizationintegration"
        unique_together = (("organization", "integration"),)
Exemplo n.º 9
0
class OrganizationIntegration(Model):
    __core__ = False

    organization = FlexibleForeignKey('sentry.Organization')
    integration = FlexibleForeignKey('sentry.Integration')
    config = EncryptedJsonField(default=dict)

    default_auth_id = BoundedPositiveIntegerField(db_index=True, null=True)
    date_added = models.DateTimeField(default=timezone.now, null=True)
    status = BoundedPositiveIntegerField(
        default=ObjectStatus.VISIBLE,
        choices=ObjectStatus.as_choices(),
    )

    class Meta:
        app_label = 'sentry'
        db_table = 'sentry_organizationintegration'
        unique_together = (('organization', 'integration'), )
Exemplo n.º 10
0
class Dashboard(Model):
    """
    A dashboard.
    """

    __core__ = True

    title = models.CharField(max_length=255)
    created_by = FlexibleForeignKey("sentry.User")
    organization = FlexibleForeignKey("sentry.Organization")
    date_added = models.DateTimeField(default=timezone.now)
    status = BoundedPositiveIntegerField(default=ObjectStatus.VISIBLE,
                                         choices=ObjectStatus.as_choices())

    class Meta:
        app_label = "sentry"
        db_table = "sentry_dashboard"
        unique_together = (("organization", "title"), )

    __repr__ = sane_repr("organization", "title")
Exemplo n.º 11
0
class WidgetDataSource(Model):
    """
    Deprecated widget class. Will be removed very soon.
    """

    __core__ = True

    widget = FlexibleForeignKey("sentry.Widget", db_constraint=False, db_index=False)
    name = models.CharField(max_length=255)
    type = BoundedPositiveIntegerField(choices=[(0, "discover_saved_search")])
    data = JSONField(default={})  # i.e. saved discover query
    order = BoundedPositiveIntegerField()
    date_added = models.DateTimeField(default=timezone.now)
    status = BoundedPositiveIntegerField(
        default=ObjectStatus.VISIBLE, choices=ObjectStatus.as_choices()
    )

    class Meta:
        app_label = "sentry"
        db_table = "sentry_widgetdatasource"
        unique_together = (("widget", "name"), ("widget", "order"))

    __repr__ = sane_repr("widget", "type", "name")
Exemplo n.º 12
0
class WidgetDataSource(Model):
    """
    A dashboard widget.
    """

    __core__ = True

    widget = FlexibleForeignKey("sentry.Widget")
    type = BoundedPositiveIntegerField(choices=WidgetDataSourceTypes.as_choices())
    name = models.CharField(max_length=255)
    data = JSONField(default={})  # i.e. saved discover query
    order = BoundedPositiveIntegerField()
    date_added = models.DateTimeField(default=timezone.now)
    status = BoundedPositiveIntegerField(
        default=ObjectStatus.VISIBLE, choices=ObjectStatus.as_choices()
    )

    class Meta:
        app_label = "sentry"
        db_table = "sentry_widgetdatasource"
        unique_together = (("widget", "name"), ("widget", "order"))

    __repr__ = sane_repr("widget", "type", "name")
Exemplo n.º 13
0
class Widget(Model):
    """
    Deprecated widget class. Will be removed very soon.
    """

    __core__ = True

    dashboard = FlexibleForeignKey("sentry.Dashboard", db_constraint=False, db_index=False)
    order = BoundedPositiveIntegerField()
    title = models.CharField(max_length=255)

    display_type = BoundedPositiveIntegerField(choices=DashboardWidgetDisplayTypes.as_choices())
    display_options = JSONField(default={})
    date_added = models.DateTimeField(default=timezone.now)
    status = BoundedPositiveIntegerField(
        default=ObjectStatus.VISIBLE, choices=ObjectStatus.as_choices()
    )

    class Meta:
        app_label = "sentry"
        db_table = "sentry_widget"
        unique_together = (("dashboard", "order"), ("dashboard", "title"))

    __repr__ = sane_repr("dashboard", "title")
Exemplo n.º 14
0
class Integration(DefaultFieldsModel):
    __include_in_export__ = False

    organizations = models.ManyToManyField(
        "sentry.Organization", related_name="integrations", through=OrganizationIntegration
    )
    projects = models.ManyToManyField(
        "sentry.Project", related_name="integrations", through=ProjectIntegration
    )
    provider = models.CharField(max_length=64)
    external_id = models.CharField(max_length=64)
    name = models.CharField(max_length=200)
    # metadata might be used to store things like credentials, but it should NOT
    # be used to store organization-specific information, as the Integration
    # instance is shared among multiple organizations
    metadata = EncryptedJsonField(default=dict)
    status = BoundedPositiveIntegerField(
        default=ObjectStatus.VISIBLE, choices=ObjectStatus.as_choices(), null=True
    )

    objects = IntegrationManager()

    class Meta:
        app_label = "sentry"
        db_table = "sentry_integration"
        unique_together = (("provider", "external_id"),)

    def get_provider(self):
        from sentry import integrations

        return integrations.get(self.provider)

    def get_installation(self, organization_id: int, **kwargs: Any) -> Any:
        return self.get_provider().get_installation(self, organization_id, **kwargs)

    def get_installations(self, **kwargs: Any) -> Sequence[Any]:
        return [
            self.get_provider().get_installation(self, organization.id, **kwargs)
            for organization in self.organizations.all()
        ]

    def has_feature(self, feature):
        return feature in self.get_provider().features

    def add_organization(self, organization, user=None, default_auth_id=None):
        """
        Add an organization to this integration.

        Returns False if the OrganizationIntegration was not created
        """
        from sentry.models import OrganizationIntegration

        try:
            org_integration, created = OrganizationIntegration.objects.get_or_create(
                organization_id=organization.id,
                integration_id=self.id,
                defaults={"default_auth_id": default_auth_id, "config": {}},
            )
            # TODO(Steve): add audit log if created
            if not created and default_auth_id:
                org_integration.update(default_auth_id=default_auth_id)
        except IntegrityError:
            logger.info(
                "add-organization-integrity-error",
                extra={
                    "organization_id": organization.id,
                    "integration_id": self.id,
                    "default_auth_id": default_auth_id,
                },
            )
            return False
        else:
            integration_added.send_robust(
                integration=self, organization=organization, user=user, sender=self.__class__
            )

            return org_integration
Exemplo n.º 15
0
class Integration(DefaultFieldsModel):
    __core__ = False

    organizations = models.ManyToManyField("sentry.Organization",
                                           related_name="integrations",
                                           through=OrganizationIntegration)
    projects = models.ManyToManyField("sentry.Project",
                                      related_name="integrations",
                                      through=ProjectIntegration)
    provider = models.CharField(max_length=64)
    external_id = models.CharField(max_length=64)
    name = models.CharField(max_length=200)
    # metadata might be used to store things like credentials, but it should NOT
    # be used to store organization-specific information, as the Integration
    # instance is shared among multiple organizations
    metadata = EncryptedJsonField(default=dict)
    status = BoundedPositiveIntegerField(default=ObjectStatus.VISIBLE,
                                         choices=ObjectStatus.as_choices(),
                                         null=True)

    class Meta:
        app_label = "sentry"
        db_table = "sentry_integration"
        unique_together = (("provider", "external_id"), )

    def get_provider(self):
        from sentry import integrations

        return integrations.get(self.provider)

    def get_installation(self, organization_id, **kwargs):
        return self.get_provider().get_installation(self, organization_id,
                                                    **kwargs)

    def has_feature(self, feature):
        return feature in self.get_provider().features

    def add_organization(self, organization, user=None, default_auth_id=None):
        """
        Add an organization to this integration.

        Returns False if the OrganizationIntegration was not created
        """
        try:
            org_integration, created = OrganizationIntegration.objects.get_or_create(
                organization_id=organization.id,
                integration_id=self.id,
                defaults={
                    "default_auth_id": default_auth_id,
                    "config": {}
                },
            )
            # TODO(Steve): add audit log if created
            if not created and default_auth_id:
                org_integration.update(default_auth_id=default_auth_id)
        except IntegrityError:
            logger.info(
                "add-organization-integrity-error",
                extra={
                    "organization_id": organization.id,
                    "integration_id": self.id,
                    "default_auth_id": default_auth_id,
                },
            )
            return False
        else:
            integration_added.send_robust(integration=self,
                                          organization=organization,
                                          user=user,
                                          sender=self.__class__)

            return org_integration

    def reauthorize(self, data):
        """
        The structure of `data` depends on the `build_integration`
        method on the integration provider.

        Each provider may have their own way of reauthorizing the
        integration.
        """
        if self.provider == "slack":
            metadata = data.get("metadata", {})
            metadata["old_access_token"] = self.metadata["access_token"]
            self.update(metadata=metadata)
Exemplo n.º 16
0
class Repository(Model, PendingDeletionMixin):
    __core__ = True

    organization_id = BoundedPositiveIntegerField(db_index=True)
    name = models.CharField(max_length=200)
    url = models.URLField(null=True)
    provider = models.CharField(max_length=64, null=True)
    external_id = models.CharField(max_length=64, null=True)
    config = JSONField(default=dict)
    status = BoundedPositiveIntegerField(
        default=ObjectStatus.VISIBLE,
        choices=ObjectStatus.as_choices(),
        db_index=True,
    )
    date_added = models.DateTimeField(default=timezone.now)
    integration_id = BoundedPositiveIntegerField(db_index=True, null=True)

    class Meta:
        app_label = 'sentry'
        db_table = 'sentry_repository'
        unique_together = (('organization_id', 'name'),
                           ('organization_id', 'provider', 'external_id'))

    __repr__ = sane_repr('organization_id', 'name', 'provider')

    _rename_fields_on_pending_delete = frozenset(['name', 'external_id'])

    def has_integration_provider(self):
        return self.provider and self.provider.startswith('integrations:')

    def get_provider(self):
        from sentry.plugins import bindings
        if self.has_integration_provider():
            provider_cls = bindings.get('integration-repository.provider').get(
                self.provider)
            return provider_cls(self.provider)

        provider_cls = bindings.get('repository.provider').get(self.provider)
        return provider_cls(self.provider)

    def generate_delete_fail_email(self, error_message):
        from sentry.utils.email import MessageBuilder

        new_context = {
            'repo': self,
            'error_message': error_message,
            'provider_name': self.get_provider().name,
        }

        return MessageBuilder(
            subject='Unable to Delete Repository Webhooks',
            context=new_context,
            template='sentry/emails/unable-to-delete-repo.txt',
            html_template='sentry/emails/unable-to-delete-repo.html',
        )

    def rename_on_pending_deletion(self, fields=None):
        # Due to the fact that Repository is shown to the user
        # as it is pending deletion, this is added to display the fields
        # correctly to the user.
        self.config['pending_deletion_name'] = self.name
        super(Repository, self).rename_on_pending_deletion(fields, ['config'])

    def reset_pending_deletion_field_names(self):
        del self.config['pending_deletion_name']
        super(Repository, self).reset_pending_deletion_field_names(['config'])
Exemplo n.º 17
0
class Integration(Model):
    __core__ = False

    organizations = models.ManyToManyField('sentry.Organization',
                                           related_name='integrations',
                                           through=OrganizationIntegration)
    projects = models.ManyToManyField('sentry.Project',
                                      related_name='integrations',
                                      through=ProjectIntegration)
    provider = models.CharField(max_length=64)
    external_id = models.CharField(max_length=64)
    name = models.CharField(max_length=200)
    # metadata might be used to store things like credentials, but it should NOT
    # be used to store organization-specific information, as the Integration
    # instance is shared among multiple organizations
    metadata = EncryptedJsonField(default=dict)
    status = BoundedPositiveIntegerField(
        default=ObjectStatus.VISIBLE,
        choices=ObjectStatus.as_choices(),
        null=True,
    )
    date_added = models.DateTimeField(default=timezone.now, null=True)

    class Meta:
        app_label = 'sentry'
        db_table = 'sentry_integration'
        unique_together = (('provider', 'external_id'), )

    def get_provider(self):
        from sentry import integrations
        return integrations.get(self.provider)

    def get_installation(self, organization_id, **kwargs):
        return self.get_provider().get_installation(self, organization_id,
                                                    **kwargs)

    def has_feature(self, feature):
        return feature in self.get_provider().features

    def add_organization(self, organization, user=None, default_auth_id=None):
        """
        Add an organization to this integration.

        Returns False if the OrganizationIntegration was not created
        """
        # TODO(adhiraj): Remove when callsites in sentry-plugins are updated.
        if isinstance(organization, int):
            from sentry.models import Organization
            organization = Organization.objects.get(id=organization)

        try:
            with transaction.atomic():
                integration = OrganizationIntegration.objects.create(
                    organization_id=organization.id,
                    integration_id=self.id,
                    default_auth_id=default_auth_id,
                    config={},
                )
        except IntegrityError:
            return False
        else:
            integration_added.send_robust(
                integration=self,
                organization=organization,
                user=user,
                sender=self.__class__,
            )

        return integration
Exemplo n.º 18
0
class Integration(Model):
    __core__ = False

    organizations = models.ManyToManyField('sentry.Organization',
                                           related_name='integrations',
                                           through=OrganizationIntegration)
    projects = models.ManyToManyField('sentry.Project',
                                      related_name='integrations',
                                      through=ProjectIntegration)
    provider = models.CharField(max_length=64)
    external_id = models.CharField(max_length=64)
    name = models.CharField(max_length=200)
    # metadata might be used to store things like credentials, but it should NOT
    # be used to store organization-specific information, as the Integration
    # instance is shared among multiple organizations
    metadata = EncryptedJsonField(default=lambda: {})
    status = BoundedPositiveIntegerField(
        default=ObjectStatus.VISIBLE,
        choices=ObjectStatus.as_choices(),
        null=True,
    )
    date_added = models.DateTimeField(default=timezone.now, null=True)

    class Meta:
        app_label = 'sentry'
        db_table = 'sentry_integration'
        unique_together = (('provider', 'external_id'),)

    def get_provider(self):
        from sentry import integrations
        return integrations.get(self.provider)

    def get_installation(self, organization_id=None, project_id=None, **kwargs):
        return self.get_provider().get_installation(self, organization_id, project_id, **kwargs)

    def has_feature(self, feature):
        return feature in self.get_provider().features

    def add_organization(self, organization_id, default_auth_id=None, config=None):
        """
        Add an organization to this integration.

        Returns False if the OrganizationIntegration was not created
        """
        try:
            with transaction.atomic():
                return OrganizationIntegration.objects.create(
                    organization_id=organization_id,
                    integration_id=self.id,
                    default_auth_id=default_auth_id,
                    config=config or {},
                )
        except IntegrityError:
            return False

    def add_project(self, project_id, config=None):
        """
        Add a project to this integration. Requires that a
        OrganizationIntegration must exist before the project can be added.

        Returns False iff the ProjectIntegration was not created
        """
        from sentry.models import Project
        org_id_queryset = Project.objects \
            .filter(id=project_id) \
            .values_list('organization_id', flat=True)
        org_integration = OrganizationIntegration.objects.filter(
            organization_id=org_id_queryset,
            integration=self,
        )

        if not org_integration.exists():
            return False

        try:
            with transaction.atomic():
                return ProjectIntegration.objects.create(
                    project_id=project_id,
                    integration_id=self.id,
                    config=config or {},
                )
        except IntegrityError:
            return False
Exemplo n.º 19
0
class Repository(Model, PendingDeletionMixin):
    __include_in_export__ = True

    organization_id = BoundedPositiveIntegerField(db_index=True)
    name = models.CharField(max_length=200)
    url = models.URLField(null=True)
    provider = models.CharField(max_length=64, null=True)
    external_id = models.CharField(max_length=64, null=True)
    config = JSONField(default=dict)
    status = BoundedPositiveIntegerField(default=ObjectStatus.VISIBLE,
                                         choices=ObjectStatus.as_choices(),
                                         db_index=True)
    date_added = models.DateTimeField(default=timezone.now)
    integration_id = BoundedPositiveIntegerField(db_index=True, null=True)

    class Meta:
        app_label = "sentry"
        db_table = "sentry_repository"
        unique_together = (
            ("organization_id", "name"),
            ("organization_id", "provider", "external_id"),
        )

    __repr__ = sane_repr("organization_id", "name", "provider")

    _rename_fields_on_pending_delete = frozenset(["name", "external_id"])

    def has_integration_provider(self):
        return self.provider and self.provider.startswith("integrations:")

    def get_provider(self):
        from sentry.plugins.base import bindings

        if self.has_integration_provider():
            provider_cls = bindings.get("integration-repository.provider").get(
                self.provider)
            return provider_cls(self.provider)

        provider_cls = bindings.get("repository.provider").get(self.provider)
        return provider_cls(self.provider)

    def generate_delete_fail_email(self, error_message):
        from sentry.utils.email import MessageBuilder

        new_context = {
            "repo": self,
            "error_message": error_message,
            "provider_name": self.get_provider().name,
        }

        return MessageBuilder(
            subject="Unable to Delete Repository Webhooks",
            context=new_context,
            template="sentry/emails/unable-to-delete-repo.txt",
            html_template="sentry/emails/unable-to-delete-repo.html",
        )

    def rename_on_pending_deletion(
        self,
        fields: set[str] | None = None,
        extra_fields_to_save: list[str] | None = None,
    ) -> None:
        # Due to the fact that Repository is shown to the user
        # as it is pending deletion, this is added to display the fields
        # correctly to the user.
        self.config["pending_deletion_name"] = self.name
        super().rename_on_pending_deletion(fields, ["config"])

    def reset_pending_deletion_field_names(
        self,
        extra_fields_to_save: list[str] | None = None,
    ) -> bool:
        del self.config["pending_deletion_name"]
        return super().reset_pending_deletion_field_names(["config"])