-
-
Notifications
You must be signed in to change notification settings - Fork 7.5k
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
invites: Do not show streams if user cannot subscribe others. #25739
Conversation
@alya can you please review? |
Hm, I feel like the banner will be a bit confusing if you don't know about the feature to configure streams for new users in the first place. Maybe we should do something like this?
|
I'd also just put it at the top where our banners generally go -- I don't think it needs to be in the same place as the stream config. |
Will update the banner. Just one thing to clear, we do not add users to default streams in this case due to recent API changes. Since user is not allowed to add users to the streams, we just do not allow passing anything inside Do we want to change this to set |
That would make the most sense to me. |
fcf571f
to
830c42c
Compare
7530e85
to
921ab8a
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.
Updated the PR to have the new message and the message to be on top. Also added commit to subscribe the user to default streams even when the user who invited does not have permission to subscribe others.
Also, added commits to use subscribe_to_default_streams
parameter such that user is subscribed to default streams at the time of creation of account and not at the time of inviting them. Have posted some questions related to API for Tim.
zerver/views/invite.py
Outdated
@@ -54,6 +53,7 @@ def invite_users_backend( | |||
default=PreregistrationUser.INVITE_AS["MEMBER"], | |||
), | |||
stream_ids: List[int] = REQ(json_validator=check_list(check_int)), | |||
subscribe_to_default_streams: bool = REQ(json_validator=check_bool, default=True), |
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 am not sure what would be the best default value here. Since the default value for stream_ids
is []
, I have kept the default value for subscribe_to_default_streams
to be True
.
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.
Hmm, on the other hand False
might be nicer in the sense that with True
default, if you pass non-empty stream_ids
, you have to also pass subscribe_to_default_streams
or you'll run into the error below due to if len(stream_ids) and subscribe_to_default_streams:
, right?
While with the default being False
, you can just pass stream_ids
without worrying about the other parameter's default getting in the way. Perhaps that's more logical? Not sure... 🤔
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.
Thinking about it more, I kinda agree that False
can be a better default. Updated the PR for now. Can change it again if feedback from others suggests otherwise.
Do we want also want to change the DB level default for this then?
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 True
might be fine as a database-level default, but I think we need a RunPython
migration step to make sure that it's set correctly for preexisting invitation objects -- presumably any that had stream_ids
set should have a value of True
.
While you're it it, we might want to do a multi-step migration where we first add a null=True
field, then backfill it, and then make it non-null; these can be big tables.
zerver/views/invite.py
Outdated
@@ -74,6 +74,9 @@ def invite_users_backend( | |||
|
|||
invitee_emails = get_invitee_emails_set(invitee_emails_raw) | |||
|
|||
if len(stream_ids) and subscribe_to_default_streams: | |||
raise JsonableError(_("Invalid parameters")) |
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.
We currently do not allow user to pass non empty list in stream_ids
and subscribe_to_default_streams
as True
together. I cannot think of a concise error message, so would love to have some suggestions in here.
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.
"Invalid parameters: stream_ids and subscribe_to_default_streams are mutually exclusive"
. Something like that perhaps?
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.
Yes, this is better than "Invalid parameters". Updated the PR.
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 works for me; I think @laurynmm might be working on a very similar string this week related to the stream/channel migration, so ideally we'd make a shared exception class that just takes a list of parameters and uses common code? Not sure.
zerver/models.py
Outdated
@@ -2367,6 +2367,7 @@ class PreregistrationUser(models.Model): | |||
full_name_validated = models.BooleanField(default=False) | |||
referred_by = models.ForeignKey(UserProfile, null=True, on_delete=CASCADE) | |||
streams = models.ManyToManyField("Stream") | |||
subscribe_to_default_streams = models.BooleanField(default=True) |
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.
Do we want this to be named something like subscribe_to_default_streams_only
?
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.
subscribe_to_exactly_default_streams
would be most clear; can you do an "api design" thread about it?
Hello @zulip/server-onboarding members, this pull request was labeled with the "area: invitations" label, so you may want to check it out! |
Hey, @sahil839, are there any remaining product questions here or is it just the technical details that need to be discussed? |
I don't think so. I have already updated the PR as per Alya's last feedback on the banner and the behavior to subscribe to default streams at the time of actual account creation and not at the time of invitation was also discussed with both Tim and Alya. I will add the "QA needed" label though, so that this will be tested someone else too. |
@mateuszmandera Can you do an initial review of this, especially the backend part? |
zerver/views/invite.py
Outdated
|
||
# We would subscribe the invited user to default streams even when the user | ||
# inviting them does not have permission to subscribe others. | ||
streams = get_default_streams_for_realm(user_profile.realm_id) |
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.
Why is this the desired behavior specifically only in the case of not user_profile.can_subscribe_other_users() and stream is empty
, but not in the case of user_profile.can_subscribe_other_users() and streams is empty
? The "consistent" way would be to do streams = get_default_streams_for_realm(user_profile.realm_id)
whenever streams
was not provided.
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 added this as discussed in this comment. We do not want to subscribe users to streams when stream_ids
is passed as empty explicitly. But in case of not user_profile.can_subscribe_other_users
we do not allow stream_ids
to be passed as non-empty list and in such case we do not show any UI for selecting streams to users and thus want the invited users to be subscribed to default streams.
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 guess @mateuszmandera recent work in #29556 also provides a very clear user case for having it be empty.
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.
And as we also add subscribe_to_default_streams
parameter, we can probably allow users without permission to subscribe others, to set the parameter as false and not subscribe the new user to default streams. Though as of this PR, we do not allow to user to deselect the subscribe_to_default_streams
parameter if the user is not allowed to subscribe others to streams.
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.
Looks reasonable to me - didn't look carefully at tests yet though. Posted a couple more comments for now.
zerver/views/invite.py
Outdated
@@ -54,6 +53,7 @@ def invite_users_backend( | |||
default=PreregistrationUser.INVITE_AS["MEMBER"], | |||
), | |||
stream_ids: List[int] = REQ(json_validator=check_list(check_int)), | |||
subscribe_to_default_streams: bool = REQ(json_validator=check_bool, default=True), |
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.
Hmm, on the other hand False
might be nicer in the sense that with True
default, if you pass non-empty stream_ids
, you have to also pass subscribe_to_default_streams
or you'll run into the error below due to if len(stream_ids) and subscribe_to_default_streams:
, right?
While with the default being False
, you can just pass stream_ids
without worrying about the other parameter's default getting in the way. Perhaps that's more logical? Not sure... 🤔
zerver/views/invite.py
Outdated
@@ -74,6 +74,9 @@ def invite_users_backend( | |||
|
|||
invitee_emails = get_invitee_emails_set(invitee_emails_raw) | |||
|
|||
if len(stream_ids) and subscribe_to_default_streams: | |||
raise JsonableError(_("Invalid parameters")) |
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.
"Invalid parameters: stream_ids and subscribe_to_default_streams are mutually exclusive"
. Something like that perhaps?
d80230d
to
c72d3be
Compare
c72d3be
to
c6ddce9
Compare
c6ddce9
to
4f97bb5
Compare
Updated the PR. Posted inline comments as well to respond the feedback and mentioning the changes done in brief below.
|
132baea
to
b881cad
Compare
b881cad
to
bc5db7a
Compare
Logic looks good, let's make the migration safe and then I think we should be able to merge this. |
8aa7f26
to
f5e077c
Compare
Updated the migration to use batching. |
…thers. This commit changes the code to subscribe the invited user to default streams even if the user who invited the new user was not allowed to subscribe others to streams.
We do not show the streams list in invite modal if the user does not have permission to subscribe others to stream and show a notice mentioning it.
Could you please post an up-to-date screenshot, including the other banners we show at the top now, to make it easy to review how looks all together? |
f5e077c
to
f3f0576
Compare
I pushed to update the API feature level. I struggled to figure out why the migration query is what it is in this PR -- The core logic change is this:
I feel like there are 3 case:
OK so I think this is correct ... but let me make that clear in the code comments. |
This commit adds include_realm_default_subscriptions parameter to the invite endpoints and the corresponding field in PreregistrationUser and MultiuseInvite objects. This field will be used to subscribe the new users to the default streams at the time of account creation and not to the streams that were default when sending the invite.
This commit adds code to use include_default_realm_subscriptions when user selects "Subscribe to default streams" checkbox in the invite modal instead of passing the stream ids of default streams.
f3f0576
to
32f614c
Compare
OK, added a very detailed docstring for the migration as part of convincing myself that its logic is correct. I renumbered the API documentation and marked this to merge once CI passes, thanks for all the work on this @sahil839! I also did some copyediting on the docs; one detail worth highlighting is that we should never just say "the user" in API docs; "the current user" or "the target user" is much clearer. |
I guess I can review post-merge. |
# If the Preregistration object didn't explicitly list some streams (it | ||
# happens when user directly signs up without any invitation), we add the | ||
# default streams for the realm. Note that we are fine with "slim" Stream | ||
# objects for calling bulk_add_subscriptions and add_new_user_history, | ||
# which we verify in StreamSetupTest tests that check query counts. |
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 comment is now a lie. @sahil839, can you update it?
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.
Yes. Opened #30165.
We do not show the streams list in invite modal if the user does not have permission to subscribe others to stream.
Screenshots and screen captures:
Self-review checklist
(variable names, code reuse, readability, etc.).
Communicate decisions, questions, and potential concerns.
Individual commits are ready for review (see commit discipline).
Completed manual review and testing of the following: