Esempio n. 1
0
    def __call__(self, request):
        # Assign a random unique ID to the request. This will be used to associate multiple object changes made during
        # the same request.
        request.id = uuid.uuid4()

        # Process the request with change logging enabled
        with change_logging(request):
            response = self.get_response(request)

        return response
Esempio n. 2
0
def refresh_datasource_content(model_name, record, request, job_result, delete=False):
    """Invoke the refresh callbacks for every content type registered for this model.

    Note that these callback functions are invoked regardless of whether a given model instance actually is flagged
    as providing each content type; this is intentional, as there may be cleanup required if a model was previously
    providing content but has now been changed to no longer provide that content.

    Args:
        model_name (str): Identifier of the datasource owner, such as "extras.gitrepository"
        record (models.Model): Datasource model instance, such as a GitRepository record
        request (HttpRequest): Initiating request for this refresh, optional, used for change logging if provided
        job_result (JobResult): Passed through to the callback functions to use with logging their actions.
        delete (bool): True if the record is being deleted; False if it is being created/updated.
    """
    job_result.log(
        f"Refreshing data provided by {record}...",
        level_choice=LogLevelChoices.LOG_INFO,
    )
    job_result.save()
    if request:
        with change_logging(request):
            for entry in get_datasource_contents(model_name):
                job_result.log(f"Refreshing {entry.name}...", level_choice=LogLevelChoices.LOG_INFO)
                try:
                    entry.callback(record, job_result, delete=delete)
                except Exception as exc:
                    job_result.log(
                        f"Error while refreshing {entry.name}: {exc}",
                        level_choice=LogLevelChoices.LOG_FAILURE,
                    )
                    job_result.set_status(JobResultStatusChoices.STATUS_ERRORED)
                job_result.save()
            job_result.log(
                f"Data refresh from {record} complete!",
                level_choice=LogLevelChoices.LOG_INFO,
            )
            job_result.save()
    else:
        for entry in get_datasource_contents(model_name):
            job_result.log(f"Refreshing {entry.name}...", level_choice=LogLevelChoices.LOG_INFO)
            try:
                entry.callback(record, job_result, delete=delete)
            except Exception as exc:
                job_result.log(
                    f"Error while refreshing {entry.name}: {exc}",
                    level_choice=LogLevelChoices.LOG_FAILURE,
                )
                job_result.set_status(JobResultStatusChoices.STATUS_ERRORED)
            job_result.save()
        job_result.log(
            f"Data refresh from {record} complete!",
            level_choice=LogLevelChoices.LOG_INFO,
        )
        job_result.save()
Esempio n. 3
0
    def test_webhooks_snapshot_on_delete(self):
        request_id = uuid.uuid4()
        webhook = Webhook.objects.get(type_create=True)
        timestamp = str(timezone.now())

        def mock_send(_, request, **kwargs):
            # Validate the outgoing request body
            body = json.loads(request.body)
            self.assertEqual(body["data"]["name"], "Site 1")
            self.assertEqual(body["snapshots"]["prechange"]["name"], "Site 1")
            self.assertEqual(body["snapshots"]["postchange"], None)
            self.assertEqual(
                body["snapshots"]["differences"]["removed"]["name"], "Site 1")
            self.assertEqual(body["snapshots"]["differences"]["added"], None)

            class FakeResponse:
                ok = True
                status_code = 200

            return FakeResponse()

        # Patch the Session object with our mock_send() method, then process the webhook for sending
        with patch.object(Session, "send", mock_send):
            request = mock.MagicMock()
            request.user = self.user
            request.id = request_id

            with change_logging(request):
                site = Site(name="Site 1", slug="site-1")
                site.save()

                # deepcopy instance state to be used by SiteSerializer and get_snapshots
                temp_site = deepcopy(site)
                site.delete()

                serializer = SiteSerializer(temp_site,
                                            context={"request": None})
                snapshots = get_snapshots(
                    temp_site, ObjectChangeActionChoices.ACTION_DELETE)

                process_webhook(
                    webhook.pk,
                    serializer.data,
                    Site._meta.model_name,
                    ObjectChangeActionChoices.ACTION_CREATE,
                    timestamp,
                    self.user.username,
                    request_id,
                    snapshots,
                )
Esempio n. 4
0
    def test_webhooks_process_webhook_on_update(self):
        """
        Mock a Session.send to inspect the result of `process_webhook()`.
        Note that process_webhook is called directly, not via a celery task.
        """

        request_id = uuid.uuid4()
        webhook = Webhook.objects.get(type_create=True)
        timestamp = str(timezone.now())

        def mock_send(_, request, **kwargs):
            """
            A mock implementation of Session.send() to be used for testing.
            Always returns a 200 HTTP response.
            """
            signature = generate_signature(request.body, webhook.secret)

            # Validate the outgoing request headers
            self.assertEqual(request.headers["Content-Type"],
                             webhook.http_content_type)
            self.assertEqual(request.headers["X-Hook-Signature"], signature)
            self.assertEqual(request.headers["X-Foo"], "Bar")

            # Validate the outgoing request body
            body = json.loads(request.body)
            self.assertEqual(body["event"], "created")
            self.assertEqual(body["timestamp"], timestamp)
            self.assertEqual(body["model"], "site")
            self.assertEqual(body["username"], "testuser")
            self.assertEqual(body["request_id"], str(request_id))
            self.assertEqual(body["data"]["name"], "Site Update")
            self.assertEqual(body["data"]["status"]["value"],
                             self.planned_status.slug)
            self.assertEqual(body["data"]["region"]["slug"],
                             self.region_two.slug)
            self.assertEqual(body["snapshots"]["prechange"]["name"], "Site 1")
            self.assertEqual(body["snapshots"]["prechange"]["status"]["value"],
                             self.active_status.slug)
            self.assertEqual(body["snapshots"]["prechange"]["region"]["slug"],
                             self.region_one.slug)
            self.assertEqual(body["snapshots"]["postchange"]["name"],
                             "Site Update")
            self.assertEqual(
                body["snapshots"]["postchange"]["status"]["value"],
                self.planned_status.slug)
            self.assertEqual(body["snapshots"]["postchange"]["region"]["slug"],
                             self.region_two.slug)
            self.assertEqual(
                body["snapshots"]["differences"]["removed"]["name"], "Site 1")
            self.assertEqual(body["snapshots"]["differences"]["added"]["name"],
                             "Site Update")

            class FakeResponse:
                ok = True
                status_code = 200

            return FakeResponse()

        # Patch the Session object with our mock_send() method, then process the webhook for sending
        with patch.object(Session, "send", mock_send):
            self.client.force_login(self.user)

            request = mock.MagicMock()
            request.user = self.user
            request.id = request_id

            with change_logging(request):
                site = Site(name="Site 1",
                            slug="site-1",
                            status=self.active_status,
                            region=self.region_one)
                site.save()

                site.name = "Site Update"
                site.status = self.planned_status
                site.region = self.region_two
                site.save()

                serializer = SiteSerializer(site, context={"request": None})
                snapshots = get_snapshots(
                    site, ObjectChangeActionChoices.ACTION_UPDATE)

                process_webhook(
                    webhook.pk,
                    serializer.data,
                    Site._meta.model_name,
                    ObjectChangeActionChoices.ACTION_CREATE,
                    timestamp,
                    self.user.username,
                    request_id,
                    snapshots,
                )
Esempio n. 5
0
    def test_webhooks_snapshot_without_model_api_serializer(
            self, get_serializer_for_model):
        def get_serializer(model_class):
            raise SerializerNotFound

        get_serializer_for_model.side_effect = get_serializer

        request_id = uuid.uuid4()
        webhook = Webhook.objects.get(type_create=True)
        timestamp = str(timezone.now())

        def mock_send(_, request, **kwargs):

            # Validate the outgoing request body
            body = json.loads(request.body)

            self.assertEqual(body["snapshots"]["prechange"]["status"],
                             str(self.active_status.id))
            self.assertEqual(body["snapshots"]["prechange"]["region"],
                             str(self.region_one.id))
            self.assertEqual(body["snapshots"]["postchange"]["name"],
                             "Site Update")
            self.assertEqual(body["snapshots"]["postchange"]["status"],
                             str(self.planned_status.id))
            self.assertEqual(body["snapshots"]["postchange"]["region"],
                             str(self.region_two.id))
            self.assertEqual(
                body["snapshots"]["differences"]["removed"]["name"], "Site 1")
            self.assertEqual(body["snapshots"]["differences"]["added"]["name"],
                             "Site Update")

            class FakeResponse:
                ok = True
                status_code = 200

            return FakeResponse()

        with patch.object(Session, "send", mock_send):
            self.client.force_login(self.user)

            request = mock.MagicMock()
            request.user = self.user
            request.id = request_id

            with change_logging(request):
                site = Site(name="Site 1",
                            slug="site-1",
                            status=self.active_status,
                            region=self.region_one)
                site.save()

                site.name = "Site Update"
                site.status = self.planned_status
                site.region = self.region_two
                site.save()

                serializer = SiteSerializer(site, context={"request": None})
                snapshots = get_snapshots(
                    site, ObjectChangeActionChoices.ACTION_UPDATE)

                process_webhook(
                    webhook.pk,
                    serializer.data,
                    Site._meta.model_name,
                    ObjectChangeActionChoices.ACTION_CREATE,
                    timestamp,
                    self.user.username,
                    request_id,
                    snapshots,
                )