Пример #1
0
    def handle_team_member_added(self, request):
        data = request.data
        channel_data = data["channelData"]
        # only care if our bot is the new member added
        matches = filter(lambda x: x["id"] == data["recipient"]["id"], data["membersAdded"])
        if not matches:
            return self.respond(status=204)

        team = channel_data["team"]

        # need to keep track of the service url since we won't get it later
        signed_data = {
            "team_id": team["id"],
            "team_name": team["name"],
            "service_url": data["serviceUrl"],
        }

        # sign the params so this can't be forged
        signed_params = sign(**signed_data)

        # send welcome message to the team
        client = get_preinstall_client(data["serviceUrl"])
        card = build_welcome_card(signed_params)
        client.send_card(team["id"], card)
        return self.respond(status=201)
Пример #2
0
    def handle_member_added(self, request):
        data = request.data
        channel_data = data["channelData"]
        # only care if our bot is the new member added
        matches = filter(lambda x: x["id"] == data["recipient"]["id"],
                         data["membersAdded"])
        if not matches:
            return self.respond(status=204)

        team = channel_data["team"]

        # TODO: add try/except for request exceptions
        access_token = get_token_data()["access_token"]

        # need to keep track of the service url since we won't get it later
        signed_data = {
            "team_id": team["id"],
            "team_name": team["name"],
            "service_url": data["serviceUrl"],
            "expiration_time": int(time.time()) + INSTALL_EXPIRATION_TIME,
        }

        # sign the params so this can't be forged
        signed_params = sign(**signed_data)

        # send welcome message to the team
        client = MsTeamsPreInstallClient(access_token, data["serviceUrl"])
        card = build_welcome_card(signed_params)
        client.send_card(team["id"], card)
        return self.respond(status=201)
Пример #3
0
    def post(self, request):
        # verify_signature will raise the exception corresponding to the error
        verify_signature(request)

        data = request.data
        channel_data = data["channelData"]
        event = channel_data.get("eventType")
        # TODO: Handle other events
        if event == "teamMemberAdded":
            # only care if our bot is the new member added
            matches = filter(lambda x: x["id"] == data["recipient"]["id"],
                             data["membersAdded"])
            if matches:
                team_id = channel_data["team"]["id"]

                access_token = get_token_data()["access_token"]

                # need to keep track of the service url since we won't get it later
                signed_data = {
                    "team_id": team_id,
                    "service_url": data["serviceUrl"]
                }

                # sign the params so this can't be forged
                signed_params = sign(**signed_data)

                # send welcome message to the team
                client = MsTeamsPreInstallClient(access_token,
                                                 data["serviceUrl"])
                client.send_welcome_message(team_id, signed_params)

        return self.respond(status=200)
Пример #4
0
    def post(self, request):
        is_valid = verify_signature(request)

        if not is_valid:
            logger.error("msteams.webhook.invalid-signature")
            return self.respond(status=401)

        data = request.data
        channel_data = data["channelData"]
        event = channel_data.get("eventType")
        # TODO: Handle other events
        if event == "teamMemberAdded":
            # only care if our bot is the new member added
            matches = filter(lambda x: x["id"] == data["recipient"]["id"],
                             data["membersAdded"])
            if matches:
                # send welcome message to the team
                team_id = channel_data["team"]["id"]
                client = MsTeamsClient()
                # sign the params so this can't be forged
                signed_params = sign(team_id=team_id)
                url = u"%s?signed_params=%s" % (
                    absolute_uri("/extensions/msteams/configure/"),
                    signed_params,
                )
                # TODO: Better message
                payload = {
                    "type": "message",
                    "text": url,
                }
                client.send_message(team_id, payload)

        return self.respond(status=200)
Пример #5
0
    def assert_setup_flow(self):
        responses.reset()

        responses.add(
            responses.POST,
            u"https://smba.trafficmanager.net/amer/v3/conversations/%s/activities"
            % team_id,
            json={},
        )

        with patch("time.time") as mock_time:
            mock_time.return_value = self.start_time
            # token mock
            access_json = {"expires_in": 86399, "access_token": "my_token"}
            responses.add(
                responses.POST,
                "https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token",
                json=access_json,
            )

            params = {"signed_params": sign(**self.pipeline_state)}

            self.pipeline.bind_state(self.provider.key, self.pipeline_state)
            resp = self.client.get(self.setup_path, params)

            body = responses.calls[0].request.body
            assert body == urlencode({
                "client_id":
                "msteams-client-id",
                "client_secret":
                "msteams-client-secret",
                "grant_type":
                "client_credentials",
                "scope":
                "https://api.botframework.com/.default",
            })

            assert resp.status_code == 200
            self.assertDialogSuccess(resp)

            integration = Integration.objects.get(provider=self.provider.key)

            assert integration.external_id == team_id
            assert integration.name == "my_team"
            assert integration.metadata == {
                "access_token": "my_token",
                "service_url": "https://smba.trafficmanager.net/amer/",
                "expires_at": self.start_time + 86399 - 60 * 5,
            }
            assert OrganizationIntegration.objects.get(
                integration=integration, organization=self.organization)

            integration_url = u"organizations/{}/rules/".format(
                self.organization.slug)
            assert integration_url in responses.calls[1].request.body.decode(
                "utf-8")
            assert self.organization.name in responses.calls[
                1].request.body.decode("utf-8")
Пример #6
0
 def test_map_params_to_state(self):
     config_view = JiraExtensionConfigurationView()
     metadata = {"my_param": "test"}
     data = {"metadata": json.dumps(metadata)}
     signed_data = sign(**data)
     params = {"signed_params": signed_data}
     assert {
         "metadata": metadata
     } == config_view.map_params_to_state(params)
Пример #7
0
def build_unlinking_url(conversation_id, service_url, teams_user_id):
    signed_params = sign(
        conversation_id=conversation_id,
        service_url=service_url,
        teams_user_id=teams_user_id,
    )

    return absolute_uri(
        reverse("sentry-integration-msteams-unlink-identity",
                kwargs={"signed_params": signed_params}))
Пример #8
0
    def test_expired(self):
        with patch("time.time") as mock_time:
            mock_time.return_value = self.start_time
            self.pipeline_state["expiration_time"] = self.start_time - 1
            params = {"signed_params": sign(**self.pipeline_state)}

            self.pipeline.bind_state(self.provider.key, self.pipeline_state)
            resp = self.client.get(self.setup_path, params)

            assert resp.status_code == 200
            assert "Installation link expired" in resp.content
Пример #9
0
 def assert_setup_flow(self):
     self.login_as(self.user)
     signed_data = {"external_id": "my-external-id", "metadata": json.dumps(self.metadata)}
     params = {"signed_params": sign(**signed_data)}
     resp = self.client.get(self.configure_path, params)
     assert resp.status_code == 302
     integration = Integration.objects.get(external_id="my-external-id")
     assert integration.metadata == self.metadata
     assert OrganizationIntegration.objects.filter(
         integration=integration, organization=self.organization
     ).exists()
Пример #10
0
def build_linking_url(integration, organization, slack_id, channel_id, response_url):
    signed_params = sign(
        integration_id=integration.id,
        organization_id=organization.id,
        slack_id=slack_id,
        channel_id=channel_id,
        response_url=response_url,
    )

    return absolute_uri(
        reverse("sentry-integration-slack-link-identity", kwargs={"signed_params": signed_params})
    )
Пример #11
0
def build_linking_url(integration, organization, teams_user_id, team_id, tenant_id):
    signed_params = sign(
        integration_id=integration.id,
        organization_id=organization.id,
        teams_user_id=teams_user_id,
        team_id=team_id,
        tenant_id=tenant_id,
    )

    return absolute_uri(
        reverse("sentry-integration-msteams-link-identity", kwargs={"signed_params": signed_params})
    )
Пример #12
0
def build_linking_url(integration, organization, slack_id, channel_id, response_url):
    signed_params = sign(
        integration_id=integration.id,
        organization_id=organization.id,
        slack_id=slack_id,
        channel_id=channel_id,
        response_url=response_url,
    )

    return absolute_uri(reverse('sentry-integration-slack-link-identity', kwargs={
        'signed_params': signed_params,
    }))
    def test_renders_template_with_signed_link(self):
        self.login_as(self.owner)
        url_data = sign(
            actor_id=self.member.user_id,
            from_organization_id=self.from_organization.id,
            project_id=self.project.id,
            user_id=self.owner.id,
            transaction_id=self.transaction_id)

        resp = self.client.get(self.path + '?' + urlencode({'data': url_data}))
        assert resp.status_code == 200
        self.assertTemplateUsed(resp, 'sentry/projects/accept_project_transfer.html')
        assert resp.context['project'] == self.project
Пример #14
0
    def test_cannot_transfer_project_twice_from_same_org(self):
        self.login_as(self.owner)
        url_data = sign(
            actor_id=self.member.user_id,
            from_organization_id=self.from_organization.id,
            project_id=self.project.id,
            user_id=self.owner.id,
            transaction_id=self.transaction_id,
        )

        resp = self.client.post(self.path, data={"team": self.to_team.id, "data": url_data})
        resp = self.client.get(self.path + "?" + urlencode({"data": url_data}))
        assert resp.status_code == 400
 def test_handle_incorrect_url_data(self):
     self.login_as(self.owner)
     url_data = sign(
         actor_id=self.member.id,
         # This is bad data
         from_organization_id=9999999,
         project_id=self.project.id,
         user_id=self.owner.id,
         transaction_id=self.transaction_id)
     resp = self.client.get(self.path + '?' + urlencode({'data': url_data}))
     assert resp.status_code == 302
     resp = self.client.get(self.path)
     assert resp.status_code == 404
Пример #16
0
def build_linking_url(integration, organization, slack_id, notify_channel_id):
    signed_params = sign(
        integration_id=integration.id,
        organization_id=organization.id,
        slack_id=slack_id,
        notify_channel_id=notify_channel_id,
    )

    return absolute_uri(
        reverse('sentry-integration-slack-link-identity',
                kwargs={
                    'signed_params': signed_params,
                }))
Пример #17
0
    def test_cannot_transfer_project_twice_from_same_org(self):
        self.login_as(self.owner)
        url_data = sign(actor_id=self.member.user_id,
                        from_organization_id=self.from_organization.id,
                        project_id=self.project.id,
                        user_id=self.owner.id,
                        transaction_id=self.transaction_id)

        url = self.path + '?' + urlencode({'data': url_data})
        resp = self.client.post(url, data={'team': self.to_team.id})
        assert resp['location'] == 'http://testserver' + \
            reverse('sentry-organization-home', args=[self.to_team.organization.slug])
        resp = self.client.get(url)
        assert resp.status_code == 302
Пример #18
0
 def test_handle_incorrect_url_data(self):
     self.login_as(self.owner)
     url_data = sign(
         actor_id=self.member.id,
         # This is bad data
         from_organization_id=9999999,
         project_id=self.project.id,
         user_id=self.owner.id,
         transaction_id=self.transaction_id,
     )
     resp = self.client.get(self.path + "?" + urlencode({"data": url_data}))
     assert resp.status_code == 400
     assert resp.data["detail"] == "Project no longer exists"
     resp = self.client.get(self.path)
     assert resp.status_code == 404
Пример #19
0
    def test_transfers_project_to_correct_team(self):
        self.login_as(self.owner)
        url_data = sign(
            actor_id=self.member.user_id,
            from_organization_id=self.from_organization.id,
            project_id=self.project.id,
            user_id=self.owner.id,
            transaction_id=self.transaction_id,
        )

        resp = self.client.post(self.path, data={"team": self.to_team.id, "data": url_data})
        assert resp.status_code == 204
        p = Project.objects.get(id=self.project.id)
        assert p.organization_id == self.to_organization.id
        assert p.teams.first() == self.to_team
Пример #20
0
    def test_returns_org_options_with_signed_link(self):
        self.login_as(self.owner)
        url_data = sign(actor_id=self.member.user_id,
                        from_organization_id=self.from_organization.id,
                        project_id=self.project.id,
                        user_id=self.owner.id,
                        transaction_id=self.transaction_id)

        resp = self.client.get(self.path + '?' + urlencode({'data': url_data}))
        assert resp.status_code == 200
        assert resp.data['project']['slug'] == self.project.slug
        assert resp.data['project']['id'] == self.project.id
        assert len(resp.data['organizations']) == 2
        org_slugs = {o['slug'] for o in resp.data['organizations']}
        assert self.from_organization.slug in org_slugs
        assert self.to_organization.slug in org_slugs
Пример #21
0
    def test_transfers_project_to_correct_organization(self):
        self.login_as(self.owner)
        url_data = sign(actor_id=self.member.user_id,
                        from_organization_id=self.from_organization.id,
                        project_id=self.project.id,
                        user_id=self.owner.id,
                        transaction_id=self.transaction_id)

        url = self.path + '?' + urlencode({'data': url_data})
        resp = self.client.post(url, data={'team': self.to_team.id})
        assert resp['location'] == 'http://testserver' + \
            reverse('sentry-organization-home', args=[self.to_team.organization.slug])

        p = Project.objects.get(id=self.project.id)
        assert p.organization_id == self.to_organization.id
        assert p.team_id == self.to_team.id
Пример #22
0
    def test_non_owner_cannot_transfer_project(self):
        rando_user = self.create_user(email="*****@*****.**", is_superuser=False)
        rando_org = self.create_organization(name="supreme beans")

        self.login_as(rando_user)
        url_data = sign(
            actor_id=self.member.user_id,
            from_organization_id=rando_org.id,
            project_id=self.project.id,
            user_id=rando_user.id,
            transaction_id=self.transaction_id,
        )

        resp = self.client.post(self.path, data={"team": self.to_team.id, "data": url_data})
        assert resp.status_code == 400
        p = Project.objects.get(id=self.project.id)
        assert p.organization_id == self.from_organization.id
    def test_non_owner_cannot_transfer_project(self):
        rando_user = self.create_user(email='*****@*****.**', is_superuser=False)
        rando_org = self.create_organization(name='supreme beans')

        self.login_as(rando_user)
        url_data = sign(
            actor_id=self.member.user_id,
            from_organization_id=rando_org.id,
            project_id=self.project.id,
            user_id=rando_user.id,
            transaction_id=self.transaction_id)

        url = self.path + '?' + urlencode({'data': url_data})
        resp = self.client.post(url, data={'team': self.to_team.id})
        assert resp.status_code == 302
        p = Project.objects.get(id=self.project.id)
        assert p.organization_id == self.from_organization.id
Пример #24
0
    def get(self, request, *args, **kwargs):
        try:
            integration = get_integration_from_request(request, "jira")
        except AtlassianConnectValidationError:
            return self.get_response(
                {"error_message": "Unable to verify installation."})
        except ExpiredSignatureError:
            return self.get_response({"refresh_required": True})

        # expose a link to the configuration view
        signed_data = {
            "external_id": integration.external_id,
            "metadata": json.dumps(integration.metadata),
        }
        finish_link = u"{}.?signed_params={}".format(
            absolute_uri("/extensions/jira/configure/"), sign(**signed_data))
        return self.get_response({"finish_link": finish_link})
Пример #25
0
    def test_returns_org_options_with_signed_link(self):
        self.login_as(self.owner)
        url_data = sign(
            actor_id=self.member.user_id,
            from_organization_id=self.from_organization.id,
            project_id=self.project.id,
            user_id=self.owner.id,
            transaction_id=self.transaction_id,
        )

        resp = self.client.get(self.path + "?" + urlencode({"data": url_data}))
        assert resp.status_code == 200
        assert resp.data["project"]["slug"] == self.project.slug
        assert resp.data["project"]["id"] == self.project.id
        assert len(resp.data["organizations"]) == 2
        org_slugs = {o["slug"] for o in resp.data["organizations"]}
        assert self.from_organization.slug in org_slugs
        assert self.to_organization.slug in org_slugs
Пример #26
0
    def test_transfers_project_to_correct_organization(self):
        self.login_as(self.owner)
        url_data = sign(
            actor_id=self.member.user_id,
            from_organization_id=self.from_organization.id,
            project_id=self.project.id,
            user_id=self.owner.id,
            transaction_id=self.transaction_id,
        )

        resp = self.client.post(self.path,
                                data={
                                    'organization': self.to_organization.slug,
                                    'data': url_data
                                })
        assert resp.status_code == 204
        p = Project.objects.get(id=self.project.id)
        assert p.organization_id == self.to_organization.id
Пример #27
0
    def test_errors_when_team_and_org_provided(self):
        self.login_as(self.owner)
        url_data = sign(
            actor_id=self.member.user_id,
            from_organization_id=self.from_organization.id,
            project_id=self.project.id,
            user_id=self.owner.id,
            transaction_id=self.transaction_id,
        )

        resp = self.client.post(
            self.path,
            data={
                "organization": self.to_organization.slug,
                "team": self.to_team.id,
                "data": url_data,
            },
        )
        assert resp.status_code == 400
        assert resp.data == {"detail": "Choose either a team or an organization, not both"}
        p = Project.objects.get(id=self.project.id)
        assert p.organization_id == self.from_organization.id
Пример #28
0
    def get(self, request: Request, *args, **kwargs) -> Response:
        try:
            integration = get_integration_from_request(request, "jira")
        except AtlassianConnectValidationError:
            return self.get_response(
                {"error_message": UNABLE_TO_VERIFY_INSTALLATION})
        except ExpiredSignatureError:
            return self.get_response({"refresh_required": True})

        # expose a link to the configuration view
        signed_data = {
            "external_id": integration.external_id,
            "metadata": json.dumps(integration.metadata),
        }
        finish_link = "{}.?signed_params={}".format(
            absolute_uri("/extensions/jira/configure/"), sign(**signed_data))

        image_path = absolute_uri(
            get_asset_url("sentry", "images/sentry-glyph-black.png"))
        return self.get_response({
            "finish_link": finish_link,
            "image_path": image_path
        })
Пример #29
0
    def post(self, request, project):
        """
        Transfer a Project
        ````````````````

        Schedules a project for transfer to a new organization.

        :pparam string organization_slug: the slug of the organization the
                                          project belongs to.
        :pparam string project_slug: the slug of the project to delete.
        :param string email: email of new owner. must be an organization owner
        :auth: required
        """
        if project.is_internal_project():
            return Response(
                '{"error": "Cannot transfer projects internally used by Sentry."}',
                status=status.HTTP_403_FORBIDDEN,
            )

        email = request.data.get("email")

        if email is None:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        if not request.user.is_authenticated():
            return Response(status=status.HTTP_403_FORBIDDEN)

        try:
            owner = OrganizationMember.objects.filter(
                user__email__iexact=email,
                role=roles.get_top_dog().id,
                user__is_active=True)[0]
        except IndexError:
            return Response(
                {
                    "detail":
                    "Could not find an organization owner with that email"
                },
                status=status.HTTP_404_NOT_FOUND,
            )

        transaction_id = uuid4().hex
        url_data = sign(
            actor_id=request.user.id,
            from_organization_id=project.organization.id,
            project_id=project.id,
            user_id=owner.user_id,
            transaction_id=transaction_id,
        )

        context = {
            "email":
            email,
            "from_org":
            project.organization.name,
            "project_name":
            project.slug,
            "request_time":
            timezone.now(),
            "url":
            absolute_uri("/accept-transfer/") + "?" +
            urlencode({"data": url_data}),
            "requester":
            request.user,
        }
        MessageBuilder(
            subject="{}Request for Project Transfer".format(
                options.get("mail.subject-prefix")),
            template="sentry/emails/transfer_project.txt",
            html_template="sentry/emails/transfer_project.html",
            type="org.confirm_project_transfer_request",
            context=context,
        ).send_async([email])

        self.create_audit_entry(
            request=request,
            organization=project.organization,
            target_object=project.id,
            event=AuditLogEntryEvent.PROJECT_REQUEST_TRANSFER,
            data=project.get_audit_log_data(),
            transaction_id=transaction_id,
        )

        return Response(status=status.HTTP_204_NO_CONTENT)
Пример #30
0
    def post(self, request, project):
        """
        Transfer a Project
        ````````````````

        Schedules a project for transfer to a new organization.

        :pparam string organization_slug: the slug of the organization the
                                          project belongs to.
        :pparam string project_slug: the slug of the project to delete.
        :param string email: email of new owner. must be an organization owner
        :auth: required
        """
        if project.is_internal_project():
            return Response(
                '{"error": "Cannot transfer projects internally used by Sentry."}',
                status=status.HTTP_403_FORBIDDEN
            )

        email = request.DATA.get('email')

        if email is None:
            return Response(status=status.HTTP_400_BAD_REQUEST)

        if not request.user.is_authenticated():
            return Response(status=status.HTTP_403_FORBIDDEN)

        try:
            owner = OrganizationMember.objects.filter(
                user__email__iexact=email,
                role=roles.get_top_dog().id,
                user__is_active=True,
            )[0]
        except IndexError:
            return Response({'detail': 'Could not find owner with that email'},
                            status=status.HTTP_404_NOT_FOUND)

        transaction_id = uuid4().hex
        url_data = sign(
            actor_id=request.user.id,
            from_organization_id=project.organization.id,
            project_id=project.id,
            user_id=owner.user_id,
            transaction_id=transaction_id)

        context = {
            'email': email,
            'from_org': project.organization.name,
            'project_name': project.slug,
            'request_time': timezone.now(),
            'url':
            absolute_uri('/accept-transfer/') + '?' + urlencode({'data': url_data}),
            'requester': request.user
        }
        MessageBuilder(
            subject='%sRequest for Project Transfer' %
            (options.get('mail.subject-prefix'), ),
            template='sentry/emails/transfer_project.txt',
            html_template='sentry/emails/transfer_project.html',
            type='org.confirm_project_transfer_request',
            context=context,
        ).send_async([email])

        self.create_audit_entry(
            request=request,
            organization=project.organization,
            target_object=project.id,
            event=AuditLogEntryEvent.PROJECT_REQUEST_TRANSFER,
            data=project.get_audit_log_data(),
            transaction_id=transaction_id,
        )

        return Response(status=status.HTTP_204_NO_CONTENT)
Пример #31
0
 def send_welcome_message(self, conversation_id):
     # sign the params so this can't be forged
     signed_params = sign(team_id=conversation_id)
     url = u"%s?signed_params=%s" % (
         absolute_uri("/extensions/msteams/configure/"),
         signed_params,
     )
     # TODO: Refactor message creation
     # TODO: Tweak welcome message appearance to perfection
     logo = {
         "type": "Image",
         "url":
         "https://sentry-brand.storage.googleapis.com/sentry-glyph-black.png",
         "size": "Medium",
     }
     welcome = {
         "type": "TextBlock",
         "weight": "Bolder",
         "size": "Large",
         "text": "Welcome to Sentry for Teams!",
         "wrap": True,
     }
     description = {
         "type": "TextBlock",
         "text":
         "The Sentry app for Teams allows you to be notified in real-time when an error pops up, using customizable alert rules.",
         "wrap": True,
     }
     instruction = {
         "type":
         "TextBlock",
         "text":
         "Please click [here](%s) to get started with using Sentry for Microsoft Teams."
         % url,
         "wrap":
         True,
     }
     card = {
         "type":
         "AdaptiveCard",
         "body": [
             {
                 "type":
                 "ColumnSet",
                 "columns": [
                     {
                         "type": "Column",
                         "items": [logo],
                         "width": "auto"
                     },
                     {
                         "type": "Column",
                         "items": [welcome],
                         "width": "stretch",
                         "verticalContentAlignment": "Center",
                     },
                 ],
             },
             description,
             instruction,
         ],
         "$schema":
         "http://adaptivecards.io/schemas/adaptive-card.json",
         "version":
         "1.2",
     }
     payload = {
         "type":
         "message",
         "attachments": [{
             "contentType": "application/vnd.microsoft.card.adaptive",
             "content": card
         }],
     }
     self.send_message(conversation_id, payload)
Пример #32
0
    def handle(self, request, organization, project):
        form = self.get_form(request)

        if form.is_valid():
            email = form.cleaned_data.get('email')
            try:
                owner = OrganizationMember.objects.filter(
                    user__email__iexact=email,
                    role=roles.get_top_dog().id,
                    user__is_active=True,
                )[0]
            except IndexError:
                messages.add_message(
                    request, messages.ERROR, six.text_type(
                        _('Could not find owner with that email')))
                return self.respond('sentry/projects/transfer.html', context={'form': form})

            transaction_id = uuid4().hex
            url_data = sign(
                actor_id=request.user.id,
                from_organization_id=organization.id,
                project_id=project.id,
                user_id=owner.user_id,
                transaction_id=transaction_id)

            has_new_teams = features.has(
                'organizations:new-teams',
                organization,
                actor=request.user,
            )
            context = {
                'email': email,
                'from_org': organization.name,
                'project_name': project.slug if has_new_teams else project.name,
                'request_time': timezone.now(),
                'url':
                absolute_uri('/accept-transfer/') + '?' + urlencode({'data': url_data}),
                'requester': request.user
            }
            MessageBuilder(
                subject='%sRequest for Project Transfer' %
                (options.get('mail.subject-prefix'), ),
                template='sentry/emails/transfer_project.txt',
                html_template='sentry/emails/transfer_project.html',
                type='org.confirm_project_transfer_request',
                context=context,
            ).send_async([email])

            self.create_audit_entry(
                request=request,
                organization=project.organization,
                target_object=project.id,
                event=AuditLogEntryEvent.PROJECT_REQUEST_TRANSFER,
                data=project.get_audit_log_data(),
                transaction_id=transaction_id,
            )

            messages.add_message(
                request, messages.SUCCESS,
                _(u'A request was sent to move project %r to a different organization') %
                ((project.slug if has_new_teams else project.name).encode('utf-8'), )
            )

            return HttpResponseRedirect(
                reverse('sentry-organization-home', args=[organization.slug])
            )

        context = {
            'form': form,
        }

        return self.respond('sentry/projects/transfer.html', context)
Пример #33
0
 def test_map_params(self):
     config_view = MsTeamsExtensionConfigurationView()
     data = {"my_param": "test"}
     signed_data = sign(**data)
     params = {"signed_params": signed_data}
     assert data == config_view.map_params_to_state(params)