-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
feat(org member invite): OrganizationMemberInviteIndex endpoint #87642
Conversation
Codecov ReportAttention: Patch coverage is ✅ All tests successful. No failed tests found.
Additional details and impacted files@@ Coverage Diff @@
## master #87642 +/- ##
===========================================
+ Coverage 42.12% 87.80% +45.67%
===========================================
Files 9880 9982 +102
Lines 561201 565449 +4248
Branches 22137 22137
===========================================
+ Hits 236421 496471 +260050
+ Misses 324349 68547 -255802
Partials 431 431 |
if invite_queryset.filter(invite_status=InviteStatus.APPROVED.value).exists(): | ||
raise MemberConflictValidationError("The user %s has already been invited" % email) | ||
|
||
if not self.context.get("allow_existing_invite_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.
is this necessary if we already have a unique constraint on organization+email?
unique_together = ("organization", "email") |
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.
Might be good to surface this to the user instead of a confusing FK error? The unique constraint exists on the organizationmember model as well, so I assume this is the reasoning behind the special error.
""" | ||
List all organization member invites. | ||
""" | ||
queryset = OrganizationMemberInvite.objects.filter(organization=organization).order_by( |
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.
when this ordering happens, which invite objects are shown first? it would be nice to see the join requests first
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 it goes APPROVED -> REQUESTED_TO_BE_INVITED -> REQUESTED_TO_JOIN according to the enum
b64ebec
to
f9f4618
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.
overall looking good but i think this is such a monster endpoint that we should try to break down the logic into their own contained functions where possible
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.
more thoughts on organization, i think the logic is good though
tests/sentry/api/endpoints/test_organization_member_invite_index.py
Outdated
Show resolved
Hide resolved
tests/sentry/api/endpoints/test_organization_member_invite_index.py
Outdated
Show resolved
Hide resolved
tests/sentry/api/endpoints/test_organization_member_invite_index.py
Outdated
Show resolved
Hide resolved
tests/sentry/api/endpoints/test_organization_member_invite_index.py
Outdated
Show resolved
Hide resolved
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.
👩🏻💻
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.
nice
context={ | ||
"organization": organization, | ||
"allowed_roles": allowed_roles, | ||
"allow_retired_roles": not features.has("organizations:team-roles", organization), |
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.
nit: could remove allow_retired_roles
from context
and simply do the feature flag check where this is used inside the validator since we're already passing organization
(it's only used in validate_orgRole
)
assert response.data[1]["inviteStatus"] == "requested_to_be_invited" | ||
|
||
def test_org_owner(self): | ||
user = self.create_user("[email protected]", username="powerful mifu") |
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.
👑
if not request.access.has_scope("member:write"): | ||
queryset = queryset.filter(invite_status=InviteStatus.APPROVED.value) |
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.
forgot to comment
it seems like everyone can see the requests
sentry/static/app/views/settings/organizationMembers/organizationMembersList.tsx
Lines 332 to 356 in 751c930
{inviteRequests.length > 0 && ( | |
<Panel> | |
<PanelHeader> | |
<StyledPanelItem> | |
<div>{t('Pending Members')}</div> | |
<div>{t('Role')}</div> | |
<div>{t('Teams')}</div> | |
</StyledPanelItem> | |
</PanelHeader> | |
<PanelBody> | |
{inviteRequests.map(inviteRequest => ( | |
<InviteRequestRow | |
key={inviteRequest.id} | |
organization={organization} | |
inviteRequest={inviteRequest} | |
inviteRequestBusy={{}} | |
allRoles={currentMember?.orgRoleList ?? currentMember?.roles ?? ORG_ROLES} | |
onApprove={handleInviteRequestApprove} | |
onDeny={handleInviteRequestDeny} | |
onUpdate={data => updateInviteRequest(inviteRequest.id, data)} | |
/> | |
))} | |
</PanelBody> | |
</Panel> | |
)} |
- GET: Lists all invites (approved and requests). If org manager/admin, show all invites; otherwise, show only approved invites - POST: Create new invite, preserving member invite member functionality Created `endpoints/organization_member/utils.py` to hold values accessible to both `OrganizationMember*` and `OrganizationMemberInvite*` endpoints (at least until the end of the API rollout period).
Created
endpoints/organization_member/utils.py
to hold values accessible to bothOrganizationMember*
andOrganizationMemberInvite*
endpoints (at least until the end of the API rollout period).