Skip to content

Commit

Permalink
invites: Add option to receive direct notification.
Browse files Browse the repository at this point in the history
Previously, when a user's invitations were accepted,
they got notification from welcome bot.
However some user may not want this everytime.

Presently, there is a personal notification setting
which lets you decide if you want notification.

Fixes: #20398.
  • Loading branch information
shashank-23002 authored and Shashank Singh committed Feb 14, 2024
1 parent 86e306a commit 383656e
Show file tree
Hide file tree
Showing 14 changed files with 72 additions and 4 deletions.
1 change: 1 addition & 0 deletions corporate/tests/test_support_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@ def create_invitation(
"stream_ids": orjson.dumps([self.get_stream_id(stream, realm)]).decode(),
"invite_expires_in_minutes": invite_expires_in_minutes,
"invite_as": PreregistrationUser.INVITE_AS["MEMBER"],
"send_notification": "true",
},
subdomain=realm.string_id if realm is not None else "zulip",
)
Expand Down
5 changes: 5 additions & 0 deletions web/src/invite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ function reset_error_messages(): void {
function get_common_invitation_data(): {
csrfmiddlewaretoken: string;
invite_as: number;
send_notification: boolean;
stream_ids: string;
invite_expires_in_minutes: string;
invitee_emails?: string;
Expand All @@ -48,6 +49,7 @@ function get_common_invitation_data(): {
$<HTMLSelectElement & {type: "select-one"}>("select:not([multiple])#invite_as").val()!,
10,
);
const send_notification = $("#send_notification").is(":checked");
const raw_expires_in = $<HTMLSelectElement & {type: "select-one"}>(
"select:not([multiple])#expires_in",
).val()!;
Expand Down Expand Up @@ -76,6 +78,7 @@ function get_common_invitation_data(): {
const data = {
csrfmiddlewaretoken: csrf_token,
invite_as,
send_notification,
stream_ids: JSON.stringify(stream_ids),
invite_expires_in_minutes: JSON.stringify(expires_in),
};
Expand Down Expand Up @@ -373,6 +376,7 @@ function open_invite_user_modal(e: JQuery.ClickEvent<Document, undefined>): void
"loading-text",
$t({defaultMessage: "Inviting..."}),
);
$("#receive-invite-notification").show();
toggle_invite_submit_button();
reset_error_messages();
});
Expand All @@ -387,6 +391,7 @@ function open_invite_user_modal(e: JQuery.ClickEvent<Document, undefined>): void
$t({defaultMessage: "Generating link..."}),
);
$("#invite-user-modal .dialog_submit_button").prop("disabled", false);
$("#receive-invite-notification").hide();
reset_error_messages();
});

Expand Down
7 changes: 7 additions & 0 deletions web/templates/invite_user_modal.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@
<textarea rows="2" id="invitee_emails" name="invitee_emails" class="invitee_emails" placeholder="{{t 'One or more email addresses...' }}"></textarea>
</div>
</div>
<div class="input-group new-style" id="receive-invite-notification">
<label class="checkbox display-block">
<input type="checkbox" id="send_notification" checked/>
<span></span>
{{t "Send me a direct message when my invitation is accepted"}}
</label>
</div>
<div class="input-group">
<label for="expires_in">{{t "Invitation expires after" }}</label>
<select id="expires_in" class="invite-expires-in modal_select bootstrap-focus-style">
Expand Down
1 change: 1 addition & 0 deletions zerver/actions/create_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ def process_new_human_user(
and prereg_user is not None
and prereg_user.referred_by is not None
and prereg_user.referred_by.is_active
and prereg_user.send_notification
):
# This is a cross-realm direct message.
with override_language(prereg_user.referred_by.default_language):
Expand Down
7 changes: 6 additions & 1 deletion zerver/actions/invites.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ def do_invite_users(
user_profile: UserProfile,
invitee_emails: Collection[str],
streams: Collection[Stream],
send_notification: bool = True,
*,
invite_expires_in_minutes: Optional[int],
invite_as: int = PreregistrationUser.INVITE_AS["MEMBER"],
Expand Down Expand Up @@ -299,7 +300,11 @@ def do_invite_users(
for email in validated_emails:
# The logged in user is the referrer.
prereg_user = PreregistrationUser(
email=email, referred_by=user_profile, invited_as=invite_as, realm=user_profile.realm
email=email,
referred_by=user_profile,
invited_as=invite_as,
realm=user_profile.realm,
send_notification=send_notification,
)
prereg_user.save()
stream_ids = [stream.id for stream in streams]
Expand Down
18 changes: 18 additions & 0 deletions zerver/migrations/0497_preregistrationuser_send_notification.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.2.9 on 2024-02-03 20:50

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("zerver", "0496_alter_scheduledmessage_read_by_sender"),
]

operations = [
migrations.AddField(
model_name="preregistrationuser",
name="send_notification",
field=models.BooleanField(default=True, null=True),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.2.9 on 2024-02-09 13:27

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("zerver", "0497_preregistrationuser_send_notification"),
]

operations = [
migrations.AlterField(
model_name="preregistrationuser",
name="send_notification",
field=models.BooleanField(default=True),
),
]
2 changes: 2 additions & 0 deletions zerver/models/prereg_users.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class PreregistrationUser(models.Model):
full_name = models.CharField(max_length=UserProfile.MAX_NAME_LENGTH, null=True)
full_name_validated = models.BooleanField(default=False)
referred_by = models.ForeignKey(UserProfile, null=True, on_delete=CASCADE)
send_notification = models.BooleanField(default=True)
streams = models.ManyToManyField("zerver.Stream")
invited_at = models.DateTimeField(auto_now=True)
realm_creation = models.BooleanField(default=False)
Expand All @@ -90,6 +91,7 @@ class PreregistrationUser(models.Model):

# These values should be consistent with the values
# in settings_config.user_role_values.

INVITE_AS = dict(
REALM_OWNER=100,
REALM_ADMIN=200,
Expand Down
1 change: 1 addition & 0 deletions zerver/tests/test_auth_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -1887,6 +1887,7 @@ def test_social_auth_invited_as_admin_but_expired(self) -> None:
iago,
[email],
[],
send_notification=True,
invite_expires_in_minutes=invite_expires_in_minutes,
invite_as=PreregistrationUser.INVITE_AS["REALM_ADMIN"],
)
Expand Down
1 change: 1 addition & 0 deletions zerver/tests/test_i18n.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ def check_translation(phrase: str, request_type: str, *args: Any, **kwargs: Any)
"invitee_emails": "new-email@zulip.com",
"stream_ids": orjson.dumps([stream.id]).decode(),
"invite_expires_in_minutes": invite_expires_in_minutes,
"send_notification": "true",
},
)

Expand Down
9 changes: 7 additions & 2 deletions zerver/tests/test_invite.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ def invite(
self,
invitee_emails: str,
stream_names: Sequence[str],
send_notification: bool = True,
invite_expires_in_minutes: Optional[int] = INVITATION_LINK_VALIDITY_MINUTES,
body: str = "",
invite_as: int = PreregistrationUser.INVITE_AS["MEMBER"],
Expand All @@ -195,6 +196,7 @@ def invite(
"/json/invites",
{
"invitee_emails": invitee_emails,
"send_notification": "true" if send_notification else "false",
"invite_expires_in_minutes": invite_expires_in,
"stream_ids": orjson.dumps(stream_ids).decode(),
"invite_as": invite_as,
Expand Down Expand Up @@ -1507,7 +1509,10 @@ def test_send_more_than_one_invite_to_same_user(self) -> None:
lear = get_realm("lear")
lear_user = self.lear_user("cordelia")
do_invite_users(
lear_user, ["foo@zulip.com"], [], invite_expires_in_minutes=invite_expires_in_minutes
lear_user,
["foo@zulip.com"],
[],
invite_expires_in_minutes=invite_expires_in_minutes,
)

invites = PreregistrationUser.objects.filter(email__iexact="foo@zulip.com")
Expand Down Expand Up @@ -2176,7 +2181,7 @@ def test_resend_never_expiring_invitation(self) -> None:
self.login("iago")
invitee = "resend@zulip.com"

self.assert_json_success(self.invite(invitee, ["Denmark"], None))
self.assert_json_success(self.invite(invitee, ["Denmark"], True, None))
prereg_user = PreregistrationUser.objects.get(email=invitee)

# Verify and then clear from the outbox the original invite email
Expand Down
1 change: 1 addition & 0 deletions zerver/tests/test_signup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3734,6 +3734,7 @@ def ldap_invite_and_signup_as(
"invitee_emails": email,
"stream_ids": orjson.dumps(stream_ids).decode(),
"invite_as": invite_as,
"send_notification": "true",
},
)
self.assert_json_success(response)
Expand Down
1 change: 1 addition & 0 deletions zerver/views/development/email_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ def generate_all_emails(request: HttpRequest) -> HttpResponse:
"invitee_emails": unregistered_email_2,
"invite_expires_in_minutes": invite_expires_in_minutes,
"stream_ids": orjson.dumps([stream.id]).decode(),
"send_notification": "true",
},
HTTP_HOST=realm.host,
)
Expand Down
4 changes: 3 additions & 1 deletion zerver/views/invite.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_success
from zerver.lib.streams import access_stream_by_id
from zerver.lib.validator import check_int, check_int_in, check_list, check_none_or
from zerver.lib.validator import check_bool, check_int, check_int_in, check_list, check_none_or
from zerver.models import MultiuseInvite, PreregistrationUser, Stream, UserProfile

# Convert INVITATION_LINK_VALIDITY_DAYS into minutes.
Expand Down Expand Up @@ -48,6 +48,7 @@ def invite_users_backend(
request: HttpRequest,
user_profile: UserProfile,
invitee_emails_raw: str = REQ("invitee_emails"),
send_notification: bool = REQ("send_notification", json_validator=check_bool, default=True),
invite_expires_in_minutes: Optional[int] = REQ(
json_validator=check_none_or(check_int), default=INVITATION_LINK_VALIDITY_MINUTES
),
Expand Down Expand Up @@ -97,6 +98,7 @@ def invite_users_backend(
user_profile,
invitee_emails,
streams,
send_notification,
invite_expires_in_minutes=invite_expires_in_minutes,
invite_as=invite_as,
)
Expand Down

0 comments on commit 383656e

Please sign in to comment.