def handle(self, request, organization): form = self.get_form(request, organization) if form.is_valid(): om, created = form.save(request.user, organization, request.META['REMOTE_ADDR']) if created: messages.add_message(request, messages.SUCCESS, _('The organization member was added.')) member_invited.send(member=om, user=request.user, sender=self) else: messages.add_message(request, messages.INFO, _('The organization member already exists.')) redirect = reverse('sentry-organization-member-settings', args=[organization.slug, om.id]) return HttpResponseRedirect(redirect) context = { 'form': form, 'is_invite': settings.SENTRY_ENABLE_INVITES, 'role_list': roles.get_all(), } return self.respond('sentry/create-organization-member.html', context)
def handle(self, request, organization): form = self.get_form(request, organization) if form.is_valid(): om, created = form.save(request.user, organization, request.META['REMOTE_ADDR']) if created: messages.add_message(request, messages.SUCCESS, _('The organization member was added.')) member_invited.send(member=om, user=request.user, sender=self) else: messages.add_message( request, messages.INFO, _('The organization member already exists.')) redirect = reverse('sentry-organization-member-settings', args=[organization.slug, om.id]) return HttpResponseRedirect(redirect) context = { 'form': form, 'is_invite': settings.SENTRY_ENABLE_INVITES, 'role_list': roles.get_all(), } return self.respond('sentry/create-organization-member.html', context)
def test_member_invited(self): user = self.create_user(email='*****@*****.**') member = self.create_member(organization=self.organization, teams=[self.team], user=user) member_invited.send(member=member, user=user, sender=type(member)) task = OrganizationOnboardingTask.objects.get( organization=self.organization, task=OnboardingTask.INVITE_MEMBER, status=OnboardingTaskStatus.PENDING, ) assert task is not None
def save(self, actor, organization, ip_address): om = super(InviteOrganizationMemberForm, self).save(commit=False) om.organization = organization om.token = om.generate_token() try: existing = OrganizationMember.objects.filter( organization=organization, user__email__iexact=om.email, user__is_active=True, )[0] except IndexError: pass else: return existing, False sid = transaction.savepoint(using='default') try: om.save() except IntegrityError: transaction.savepoint_rollback(sid, using='default') return OrganizationMember.objects.get( email__iexact=om.email, organization=organization, ), False transaction.savepoint_commit(sid, using='default') self.save_team_assignments(om) AuditLogEntry.objects.create( organization=organization, actor=actor, ip_address=ip_address, target_object=om.id, event=AuditLogEntryEvent.MEMBER_INVITE, data=om.get_audit_log_data(), ) member_invited.send(member=om, user=actor, sender=InviteOrganizationMemberForm) om.send_invite_email() return om, True
def handle(self, request, organization): can_admin, allowed_roles = self.get_allowed_roles( request, organization) all_teams = Team.objects.filter(organization=organization, status=TeamStatus.VISIBLE) form = self.get_form(request, organization, all_teams, allowed_roles) if form.is_valid(): om, created = form.save(request.user, organization, request.META['REMOTE_ADDR']) user_display = form.cleaned_data.get('email', None) if not user_display: user_display = form.cleaned_data['user'] if created: messages.add_message( request, messages.SUCCESS, _('The organization member %s was added.') % user_display) member_invited.send(member=om, user=request.user, sender=self) else: messages.add_message( request, messages.INFO, _('The organization member %s already exists.') % user_display) redirect = reverse('sentry-organization-members', args=[organization.slug]) return HttpResponseRedirect(redirect) context = { 'form': form, 'is_invite': settings.SENTRY_ENABLE_INVITES, 'role_list': [(r, r in allowed_roles) for r in roles.get_all()], 'all_teams': list(all_teams), } return self.respond('sentry/create-organization-member.html', context)
def handle(self, request, organization): can_admin, allowed_roles = self.get_allowed_roles(request, organization) all_teams = Team.objects.filter( organization=organization, status=TeamStatus.VISIBLE ) form = self.get_form(request, organization, all_teams, allowed_roles) if form.is_valid(): om, created = form.save(request.user, organization, request.META['REMOTE_ADDR']) user_display = form.cleaned_data.get('email', None) if not user_display: user_display = form.cleaned_data['user'] if created: messages.add_message(request, messages.SUCCESS, _('The organization member %s was added.') % user_display) member_invited.send(member=om, user=request.user, sender=self) else: messages.add_message(request, messages.INFO, _('The organization member %s already exists.') % user_display) redirect = reverse('sentry-organization-members', args=[organization.slug]) return HttpResponseRedirect(redirect) context = { 'form': form, 'is_invite': settings.SENTRY_ENABLE_INVITES, 'role_list': [ (r, r in allowed_roles) for r in roles.get_all() ], 'all_teams': list(all_teams), } return self.respond('sentry/create-organization-member.html', context)
def post(self, request, organization): """ Add a Member to Organization ```````````````````````````` Invite a member to the organization. :pparam string organization_slug: the slug of the organization the member will belong to :param string email: the email address to invite :param string role: the role of the new member :param array teams: the slugs of the teams the member should belong to. :auth: required """ # TODO: If the member already exists, should this still update the role and team? # For now, it doesn't, but simply returns the existing object if not features.has('organizations:invite-members', organization, actor=request.user): return Response( { 'organization': 'Your organization is not allowed to invite members' }, status=403) serializer = OrganizationMemberSerializer(data=request.DATA) if not serializer.is_valid(): return Response(serializer.errors, status=400) result = serializer.object _, allowed_roles = get_allowed_roles(request, organization) # ensure listed teams are real teams teams = list( Team.objects.filter( organization=organization, status=TeamStatus.VISIBLE, slug__in=result['teams'], )) if len(set(result['teams'])) != len(teams): return Response({'teams': 'Invalid team'}, 400) if not result['role'] in {r.id for r in allowed_roles}: return Response( {'role': 'You do not have permission to invite that role.'}, 403) # This is needed because `email` field is case sensitive, but from a user perspective, # Sentry treats email as case-insensitive ([email protected] equals [email protected]). existing = OrganizationMember.objects.filter( organization=organization, user__email__iexact=result['email'], user__is_active=True, ).exists() if existing: return Response( {'email': 'The user %s is already a member' % result['email']}, 409) om = OrganizationMember(organization=organization, email=result['email'], role=result['role']) if settings.SENTRY_ENABLE_INVITES: om.token = om.generate_token() try: with transaction.atomic(): om.save() except IntegrityError: return Response( {'email': 'The user %s is already a member' % result['email']}, 409) lock = locks.get('org:member:{}'.format(om.id), duration=5) with TimedRetryPolicy(10)(lock.acquire): self.save_team_assignments(om, teams) if settings.SENTRY_ENABLE_INVITES: om.send_invite_email() member_invited.send(member=om, user=request.user, sender=self, referrer=request.DATA.get('referrer')) self.create_audit_entry( request=request, organization_id=organization.id, target_object=om.id, data=om.get_audit_log_data(), event=AuditLogEntryEvent.MEMBER_INVITE if settings.SENTRY_ENABLE_INVITES else AuditLogEntryEvent.MEMBER_ADD, ) return Response(serialize(om), status=201)
def post(self, request, organization): """ Add a Member to Organization ```````````````````````````` Invite a member to the organization. :pparam string organization_slug: the slug of the organization the member will belong to :param string email: the email address to invite :param string role: the role of the new member :param array teams: the slugs of the teams the member should belong to. :auth: required """ # TODO: If the member already exists, should this still update the role and team? # For now, it doesn't, but simply returns the existing object if not features.has('organizations:invite-members', organization, actor=request.user): return Response( {'organization': 'Your organization is not allowed to invite members'}, status=403) serializer = OrganizationMemberSerializer(data=request.DATA) if not serializer.is_valid(): return Response(serializer.errors, status=400) result = serializer.object _, allowed_roles = get_allowed_roles(request, organization) # ensure listed teams are real teams teams = list(Team.objects.filter( organization=organization, status=TeamStatus.VISIBLE, slug__in=result['teams'], )) if len(set(result['teams'])) != len(teams): return Response({'teams': 'Invalid team'}, 400) if not result['role'] in {r.id for r in allowed_roles}: return Response({'role': 'You do not have permission to invite that role.'}, 403) # This is needed because `email` field is case sensitive, but from a user perspective, # Sentry treats email as case-insensitive ([email protected] equals [email protected]). existing = OrganizationMember.objects.filter( organization=organization, user__email__iexact=result['email'], user__is_active=True, ).exists() if existing: return Response({'email': 'The user %s is already a member' % result['email']}, 409) om = OrganizationMember( organization=organization, email=result['email'], role=result['role']) if settings.SENTRY_ENABLE_INVITES: om.token = om.generate_token() try: with transaction.atomic(): om.save() except IntegrityError: return Response({'email': 'The user %s is already a member' % result['email']}, 409) lock = locks.get('org:member:{}'.format(om.id), duration=5) with TimedRetryPolicy(10)(lock.acquire): self.save_team_assignments(om, teams) if settings.SENTRY_ENABLE_INVITES: om.send_invite_email() member_invited.send(member=om, user=request.user, sender=self) self.create_audit_entry( request=request, organization_id=organization.id, target_object=om.id, data=om.get_audit_log_data(), event=AuditLogEntryEvent.MEMBER_INVITE if settings.SENTRY_ENABLE_INVITES else AuditLogEntryEvent.MEMBER_ADD, ) return Response(serialize(om), status=201)