invite: Simplify error-handling with exceptions.

I especially like what happens to the return type of
`do_invite_users`.
This commit is contained in:
Greg Price 2017-07-24 17:02:30 -07:00
parent 28b4234227
commit b2f770c1ee
3 changed files with 24 additions and 23 deletions

View File

@ -81,7 +81,7 @@ from zerver.lib.alert_words import user_alert_words, add_user_alert_words, \
remove_user_alert_words, set_user_alert_words remove_user_alert_words, set_user_alert_words
from zerver.lib.notifications import clear_scheduled_emails from zerver.lib.notifications import clear_scheduled_emails
from zerver.lib.narrow import check_supported_events_narrow_filter from zerver.lib.narrow import check_supported_events_narrow_filter
from zerver.lib.request import JsonableError from zerver.lib.exceptions import JsonableError, ErrorCode
from zerver.lib.sessions import delete_user_sessions from zerver.lib.sessions import delete_user_sessions
from zerver.lib.upload import attachment_url_re, attachment_url_to_path_id, \ from zerver.lib.upload import attachment_url_re, attachment_url_to_path_id, \
claim_attachment, delete_message_image claim_attachment, delete_message_image
@ -3153,15 +3153,22 @@ def validate_email(user_profile, email):
return None, None return None, None
class InvitationError(JsonableError):
code = ErrorCode.INVITATION_FAILED
data_fields = ['errors', 'sent_invitations']
def __init__(self, msg, errors, sent_invitations):
# type: (Text, List[Tuple[Text, str]], bool) -> None
self._msg = msg # type: Text
self.errors = errors # type: List[Tuple[Text, str]]
self.sent_invitations = sent_invitations # type: bool
def do_invite_users(user_profile, invitee_emails, streams, body=None): def do_invite_users(user_profile, invitee_emails, streams, body=None):
# type: (UserProfile, SizedTextIterable, Iterable[Stream], Optional[str]) -> Tuple[Optional[str], Dict[str, Union[List[Tuple[Text, str]], bool]]] # type: (UserProfile, SizedTextIterable, Iterable[Stream], Optional[str]) -> None
validated_emails = [] # type: List[Text] validated_emails = [] # type: List[Text]
errors = [] # type: List[Tuple[Text, str]] errors = [] # type: List[Tuple[Text, str]]
skipped = [] # type: List[Tuple[Text, str]] skipped = [] # type: List[Tuple[Text, str]]
ret_error = None # type: Optional[str]
ret_error_data = {} # type: Dict[str, Union[List[Tuple[Text, str]], bool]]
for email in invitee_emails: for email in invitee_emails:
if email == '': if email == '':
continue continue
@ -3176,15 +3183,14 @@ def do_invite_users(user_profile, invitee_emails, streams, body=None):
skipped.append((email, email_skipped)) skipped.append((email, email_skipped))
if errors: if errors:
ret_error = _("Some emails did not validate, so we didn't send any invitations.") raise InvitationError(
ret_error_data = {'errors': errors + skipped, 'sent_invitations': False} _("Some emails did not validate, so we didn't send any invitations."),
return ret_error, ret_error_data errors + skipped, sent_invitations=False)
if skipped and len(skipped) == len(invitee_emails): if skipped and len(skipped) == len(invitee_emails):
# All e-mails were skipped, so we didn't actually invite anyone. # All e-mails were skipped, so we didn't actually invite anyone.
ret_error = _("We weren't able to invite anyone.") raise InvitationError(_("We weren't able to invite anyone."),
ret_error_data = {'errors': skipped, 'sent_invitations': False} skipped, sent_invitations=False)
return ret_error, ret_error_data
# Now that we are past all the possible errors, we actually create # Now that we are past all the possible errors, we actually create
# the PreregistrationUser objects and trigger the email invitations. # the PreregistrationUser objects and trigger the email invitations.
@ -3203,12 +3209,10 @@ def do_invite_users(user_profile, invitee_emails, streams, body=None):
lambda event: do_send_confirmation_email(prereg_user, user_profile, body)) lambda event: do_send_confirmation_email(prereg_user, user_profile, body))
if skipped: if skipped:
ret_error = _("Some of those addresses are already using Zulip, " raise InvitationError(_("Some of those addresses are already using Zulip, "
"so we didn't send them an invitation. We did send " "so we didn't send them an invitation. We did send "
"invitations to everyone else!") "invitations to everyone else!"),
ret_error_data = {'errors': skipped, 'sent_invitations': True} skipped, sent_invitations=True)
return ret_error, ret_error_data
def notify_realm_emoji(realm): def notify_realm_emoji(realm):
# type: (Realm) -> None # type: (Realm) -> None

View File

@ -37,6 +37,7 @@ class ErrorCode(AbstractEnum):
UNAUTHORIZED_PRINCIPAL = () UNAUTHORIZED_PRINCIPAL = ()
BAD_EVENT_QUEUE_ID = () BAD_EVENT_QUEUE_ID = ()
CSRF_FAILED = () CSRF_FAILED = ()
INVITATION_FAILED = ()
class JsonableError(Exception): class JsonableError(Exception):
'''A standardized error format we can turn into a nice JSON HTTP response. '''A standardized error format we can turn into a nice JSON HTTP response.

View File

@ -50,12 +50,8 @@ def json_invite_users(request, user_profile,
return json_error(_("Stream does not exist: %s. No invites were sent.") % (stream_name,)) return json_error(_("Stream does not exist: %s. No invites were sent.") % (stream_name,))
streams.append(stream) streams.append(stream)
ret_error, error_data = do_invite_users(user_profile, invitee_emails, streams, body) do_invite_users(user_profile, invitee_emails, streams, body)
return json_success()
if ret_error is not None:
return json_error(data=error_data, msg=ret_error)
else:
return json_success()
def get_invitee_emails_set(invitee_emails_raw): def get_invitee_emails_set(invitee_emails_raw):
# type: (str) -> Set[str] # type: (str) -> Set[str]