-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
feat(org member invite): OrganizationMemberInviteDetails DELETE endpoint #88587
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
audit_data = invited_member.get_audit_log_data() | ||
event_name = "INVITE_REMOVE" if invited_member.invite_approved else "INVITE_REQUEST_REMOVE" | ||
with transaction.atomic(router.db_for_write(OrganizationMemberInvite)): | ||
invited_member.delete() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I unfortunately need to move this to a method on the model to support rejecting an invite request via slack ;_;
Codecov ReportAttention: Patch coverage is ✅ All tests successful. No failed tests found.
Additional details and impacted files@@ Coverage Diff @@
## master #88587 +/- ##
==========================================
+ Coverage 81.79% 82.93% +1.13%
==========================================
Files 10204 10206 +2
Lines 575357 575882 +525
Branches 22662 22662
==========================================
+ Hits 470626 477619 +6993
+ Misses 103802 97334 -6468
Partials 929 929 |
if not request.access.has_scope("member:admin"): | ||
if not organization.flags.disable_member_invite and request.access.has_scope( | ||
"member:invite" | ||
): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we pull these out into their own variables? then checking them is a bit easier to grok
62029b8
to
d71b8b1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code quality issues
if request.user.is_authenticated and not is_active_superuser(request): | ||
try: | ||
acting_member = OrganizationMember.objects.get( | ||
organization=organization, user_id=request.user.id | ||
) | ||
except OrganizationMember.DoesNotExist: | ||
return Response({"detail": ERR_INSUFFICIENT_ROLE}, status=400) | ||
|
||
has_member_admin_scope = request.access.has_scope("member:admin") | ||
if not has_member_admin_scope: | ||
can_invite_members = request.access.has_scope("member:invite") | ||
if can_invite_members: | ||
return self._handle_deletion_by_member( | ||
request, organization, invited_member, acting_member | ||
) | ||
return Response({"detail": ERR_INSUFFICIENT_SCOPE}, status=400) | ||
else: | ||
can_manage = roles.can_manage(acting_member.role, invited_member.role) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can move this further down the method, and do all the low-hanging fruit checks and return early from there. It will make this section a lot less nested.
has_member_admin_scope = request.access.has_scope("member:admin") | ||
if not has_member_admin_scope: | ||
can_invite_members = request.access.has_scope("member:invite") | ||
if can_invite_members: | ||
return self._handle_deletion_by_member( | ||
request, organization, invited_member, acting_member | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this more readable?
has_member_admin_scope = request.access.has_scope("member:admin")
can_invite_members = request.access.has_scope("member:invite")
if not has_member_admin_scope or can_invite_members
return self._handle_deletion_by_member(
request, organization, invited_member, acting_member
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't the same logic, because users with org:admin
have member:invite
. We would enter the if statement erroneously.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll make it a little cleaner.
""" | ||
Members can remove invites that they sent | ||
""" | ||
self.login_as(self.regular_user) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how is this working if the user is not a member of the org?
i think you might need to update MemberInvitePermission
's scope_map
for DELETE
return self._handle_deletion_by_member( | ||
request, organization, invited_member, acting_member | ||
) | ||
return Response({"detail": ERR_INSUFFICIENT_SCOPE}, status=400) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should these be responding with 403 if you're not allowed to perform this action?
# prevents superuser read from deleting an invite or invite request | ||
elif not request.access.has_scope("member:admin"): | ||
return Response({"detail": ERR_INSUFFICIENT_SCOPE}, status=400) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rather than preventing superuser read (since they can't hit the endpoint anyway), i think this is preventing unauthenticated users from hitting this endpoint
raise NotImplementedError | ||
# with superuser read write separation, superuser read cannot hit this endpoint | ||
# so we can keep this as is_active_superuser | ||
if request.user.is_authenticated and not is_active_superuser(request): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe check the user is authenticated separately and early return? they should always be authenticated to proceed
@@ -140,7 +145,90 @@ def put( | |||
|
|||
return Response(serialize(invited_member, request.user), status=200) | |||
|
|||
def _remove_invite_from_db( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is almost the same as reject_invite_request
on the OrganizationMemberInvite
model. could they be collapsed into a single function?
This issue has gone three weeks without activity. In another week, I will close it. But! If you comment or otherwise update it, I will reset the clock, and if you remove the label "A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀 |
Delete an
OrganizationMemberInvite
object from the database. This is used to delete invites and reject invite requests.