Example #1
0
    def test_invite_user_signup_initial_history(self):
        # type: () -> None
        """
        Test that a new user invited to a stream receives some initial
        history but only from public streams.
        """
        self.login("*****@*****.**")
        user_profile = get_user_profile_by_email("*****@*****.**")
        private_stream_name = "Secret"
        (stream, _) = create_stream_if_needed(user_profile.realm, private_stream_name, invite_only=True)
        do_add_subscription(user_profile, stream)
        public_msg_id = self.send_message("*****@*****.**", "Denmark", Recipient.STREAM,
                                          "Public topic", "Public message")
        secret_msg_id = self.send_message("*****@*****.**", private_stream_name, Recipient.STREAM,
                                          "Secret topic", "Secret message")
        invitee = "*****@*****.**"
        self.assert_json_success(self.invite(invitee, [private_stream_name, "Denmark"]))
        self.assertTrue(find_key_by_email(invitee))

        self.submit_reg_form_for_user("alice-test", "password")
        invitee_profile = get_user_profile_by_email(invitee)
        invitee_msg_ids = [um.message_id for um in
                           UserMessage.objects.filter(user_profile=invitee_profile)]
        self.assertTrue(public_msg_id in invitee_msg_ids)
        self.assertFalse(secret_msg_id in invitee_msg_ids)
    def handle(self, *args, **options):
        # type: (*Any, **str) -> None
        old_email = options['old_email']

        if options['new_email']:
            new_email = options['new_email']
        else:
            new_email = old_email

        gravatar_url = "https://secure.gravatar.com/avatar/%s?d=identicon" % (gravatar_hash(old_email),)
        gravatar_data = requests.get(gravatar_url).content
        gravatar_file = SimpleUploadedFile('gravatar.jpg', gravatar_data, 'image/jpeg')

        try:
            user_profile = get_user_profile_by_email(old_email)
        except UserProfile.DoesNotExist:
            try:
                user_profile = get_user_profile_by_email(new_email)
            except UserProfile.DoesNotExist:
                raise CommandError("Could not find specified user")

        upload_avatar_image(gravatar_file, user_profile, old_email)
        if old_email != new_email:
            gravatar_file.seek(0)
            upload_avatar_image(gravatar_file, user_profile, new_email)

        user_profile.avatar_source = UserProfile.AVATAR_FROM_USER
        user_profile.save(update_fields=['avatar_source'])
Example #3
0
def add_bot_backend(request, user_profile, full_name=REQ(), short_name=REQ(),
                    default_sending_stream_name=REQ('default_sending_stream', default=None),
                    default_events_register_stream_name=REQ('default_events_register_stream', default=None),
                    default_all_public_streams=REQ(validator=check_bool, default=None)):
    # type: (HttpRequest, UserProfile, text_type, text_type, Optional[text_type], Optional[text_type], Optional[bool]) -> HttpResponse
    short_name += "-bot"
    email = short_name + "@" + user_profile.realm.domain
    form = CreateUserForm({'full_name': full_name, 'email': email})
    if not form.is_valid():
        # We validate client-side as well
        return json_error(_('Bad name or username'))

    try:
        get_user_profile_by_email(email)
        return json_error(_("Username already in use"))
    except UserProfile.DoesNotExist:
        pass

    if len(request.FILES) == 0:
        avatar_source = UserProfile.AVATAR_FROM_GRAVATAR
    elif len(request.FILES) != 1:
        return json_error(_("You may only upload one file at a time"))
    else:
        user_file = list(request.FILES.values())[0]
        upload_avatar_image(user_file, user_profile, email)
        avatar_source = UserProfile.AVATAR_FROM_USER

    default_sending_stream = None
    if default_sending_stream_name is not None:
        default_sending_stream = stream_or_none(default_sending_stream_name, user_profile.realm)
    if default_sending_stream and not default_sending_stream.is_public() and not \
        subscribed_to_stream(user_profile, default_sending_stream):
        return json_error(_('Insufficient permission'))

    default_events_register_stream = None
    if default_events_register_stream_name is not None:
        default_events_register_stream = stream_or_none(default_events_register_stream_name,
                                                        user_profile.realm)
    if default_events_register_stream and not default_events_register_stream.is_public() and not \
        subscribed_to_stream(user_profile, default_events_register_stream):
        return json_error(_('Insufficient permission'))


    bot_profile = do_create_user(email=email, password='',
                                 realm=user_profile.realm, full_name=full_name,
                                 short_name=short_name, active=True,
                                 bot_type=UserProfile.DEFAULT_BOT,
                                 bot_owner=user_profile,
                                 avatar_source=avatar_source,
                                 default_sending_stream=default_sending_stream,
                                 default_events_register_stream=default_events_register_stream,
                                 default_all_public_streams=default_all_public_streams)
    json_result = dict(
            api_key=bot_profile.api_key,
            avatar_url=avatar_url(bot_profile),
            default_sending_stream=get_stream_name(bot_profile.default_sending_stream),
            default_events_register_stream=get_stream_name(bot_profile.default_events_register_stream),
            default_all_public_streams=bot_profile.default_all_public_streams,
    )
    return json_success(json_result)
Example #4
0
    def test_mention_shortname(self):
        sender_user_profile = get_user_profile_by_email("*****@*****.**")
        user_profile = get_user_profile_by_email("*****@*****.**")
        msg = Message(sender=sender_user_profile, sending_client=get_client("test"))

        content = "@**hamlet**"
        self.assertEqual(msg.render_markdown(content),
                         '<p><span class="user-mention" data-user-email="*****@*****.**">@King Hamlet</span></p>')
        self.assertEqual(msg.mentions_user_ids, set([user_profile.id]))
Example #5
0
def add_bot_backend(request, user_profile, full_name_raw=REQ("full_name"), short_name=REQ(),
                    default_sending_stream_name=REQ('default_sending_stream', default=None),
                    default_events_register_stream_name=REQ('default_events_register_stream', default=None),
                    default_all_public_streams=REQ(validator=check_bool, default=None)):
    # type: (HttpRequest, UserProfile, Text, Text, Optional[Text], Optional[Text], Optional[bool]) -> HttpResponse
    short_name += "-bot"
    full_name = check_full_name(full_name_raw)
    email = '%s@%s' % (short_name, user_profile.realm.get_bot_domain())
    form = CreateUserForm({'full_name': full_name, 'email': email})
    if not form.is_valid():
        # We validate client-side as well
        return json_error(_('Bad name or username'))

    try:
        get_user_profile_by_email(email)
        return json_error(_("Username already in use"))
    except UserProfile.DoesNotExist:
        pass

    if len(request.FILES) == 0:
        avatar_source = UserProfile.AVATAR_FROM_GRAVATAR
    elif len(request.FILES) != 1:
        return json_error(_("You may only upload one file at a time"))
    else:
        avatar_source = UserProfile.AVATAR_FROM_USER

    default_sending_stream = None
    if default_sending_stream_name is not None:
        (default_sending_stream, ignored_rec, ignored_sub) = access_stream_by_name(
            user_profile, default_sending_stream_name)

    default_events_register_stream = None
    if default_events_register_stream_name is not None:
        (default_events_register_stream, ignored_rec, ignored_sub) = access_stream_by_name(
            user_profile, default_events_register_stream_name)

    bot_profile = do_create_user(email=email, password='',
                                 realm=user_profile.realm, full_name=full_name,
                                 short_name=short_name, active=True,
                                 bot_type=UserProfile.DEFAULT_BOT,
                                 bot_owner=user_profile,
                                 avatar_source=avatar_source,
                                 default_sending_stream=default_sending_stream,
                                 default_events_register_stream=default_events_register_stream,
                                 default_all_public_streams=default_all_public_streams)
    if len(request.FILES) == 1:
        user_file = list(request.FILES.values())[0]
        upload_avatar_image(user_file, user_profile, bot_profile)
    json_result = dict(
        api_key=bot_profile.api_key,
        avatar_url=avatar_url(bot_profile),
        default_sending_stream=get_stream_name(bot_profile.default_sending_stream),
        default_events_register_stream=get_stream_name(bot_profile.default_events_register_stream),
        default_all_public_streams=bot_profile.default_all_public_streams,
    )
    return json_success(json_result)
Example #6
0
 def test_invalid_pointer(self):
     """
     Posting json to /json/update_pointer with an invalid pointer returns a 400 and error
     message.
     """
     self.login("*****@*****.**")
     self.assertEqual(get_user_profile_by_email("*****@*****.**").pointer, -1)
     result = self.client.post("/json/update_pointer", {"pointer": "foo"})
     self.assert_json_error(result, "Bad value for 'pointer': foo")
     self.assertEqual(get_user_profile_by_email("*****@*****.**").pointer, -1)
Example #7
0
 def test_pointer_out_of_range(self):
     """
     Posting json to /json/update_pointer with an out of range (< 0) pointer returns a 400
     and error message.
     """
     self.login("*****@*****.**")
     self.assertEqual(get_user_profile_by_email("*****@*****.**").pointer, -1)
     result = self.client.post("/json/update_pointer", {"pointer": -2})
     self.assert_json_error(result, "Bad value for 'pointer': -2")
     self.assertEqual(get_user_profile_by_email("*****@*****.**").pointer, -1)
Example #8
0
 def test_missing_pointer(self):
     """
     Posting json to /json/update_pointer which does not contain a pointer key/value pair
     returns a 400 and error message.
     """
     self.login("*****@*****.**")
     self.assertEqual(get_user_profile_by_email("*****@*****.**").pointer, -1)
     result = self.client.post("/json/update_pointer", {"foo": 1})
     self.assert_json_error(result, "Missing 'pointer' argument")
     self.assertEqual(get_user_profile_by_email("*****@*****.**").pointer, -1)
Example #9
0
def export_avatars_local_helper(realm, output_dir, local_dir):
    # type: (Realm, Path, Path) -> None
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    count = 0
    records = []

    users = list(UserProfile.objects.filter(realm=realm))
    users += [
        get_user_profile_by_email(settings.NOTIFICATION_BOT),
        get_user_profile_by_email(settings.EMAIL_GATEWAY_BOT),
        get_user_profile_by_email(settings.WELCOME_BOT),
    ]
    for user in users:
        if user.avatar_source == UserProfile.AVATAR_FROM_GRAVATAR:
            continue
        # NOTE: There is an avatar source called AVATAR_FROM_SYSTEM,
        #       but I'm not sure we support it any more.  If we
        #       have system-generated avatars, then arguably we
        #       don't need to export them, but it's probably
        #       expedient to just copy them over.  The more
        #       common case is AVATAR_FROM_USER, which is handled
        #       here as well.  AVATAR_FROM_GRAVATAR refers to
        #       avatars hosted by gravatar.com, and for them,
        #       we have no files to worry about exporting

        avatar_hash = user_avatar_hash(user.email)
        wildcard = os.path.join(local_dir, avatar_hash + '.*')

        for local_path in glob.glob(wildcard):
            logging.info('Copying avatar file for user %s from %s' % (
                user.email, local_path))
            fn = os.path.basename(local_path)
            output_path = os.path.join(output_dir, fn)
            mkdir_p(str(os.path.dirname(output_path)))
            subprocess.check_call(["cp", "-a", str(local_path), str(output_path)])
            stat = os.stat(local_path)
            record = dict(realm_id=realm.id,
                          user_profile_id=user.id,
                          user_profile_email=user.email,
                          s3_path=fn,
                          path=fn,
                          size=stat.st_size,
                          last_modified=stat.st_mtime,
                          content_type=None)
            records.append(record)

            count += 1

            if (count % 100 == 0):
                logging.info("Finished %s" % (count,))

    with open(os.path.join(output_dir, "records.json"), "w") as records_file:
        ujson.dump(records, records_file, indent=4)
Example #10
0
 def test_api_update_pointer(self):
     """
     Same as above, but for the API view
     """
     email = "*****@*****.**"
     self.assertEqual(get_user_profile_by_email(email).pointer, -1)
     msg_id = self.send_message("*****@*****.**", "Verona", Recipient.STREAM)
     result = self.client_put("/api/v1/users/me/pointer", {"pointer": msg_id},
                              **self.api_auth(email))
     self.assert_json_success(result)
     self.assertEqual(get_user_profile_by_email(email).pointer, msg_id)
Example #11
0
 def test_update_pointer(self):
     """
     Posting a pointer to /update (in the form {"pointer": pointer}) changes
     the pointer we store for your UserProfile.
     """
     self.login("*****@*****.**")
     self.assertEqual(get_user_profile_by_email("*****@*****.**").pointer, -1)
     msg_id = self.send_message("*****@*****.**", "Verona", Recipient.STREAM)
     result = self.client.post("/json/update_pointer", {"pointer": msg_id})
     self.assert_json_success(result)
     self.assertEqual(get_user_profile_by_email("*****@*****.**").pointer, msg_id)
Example #12
0
 def test_do_change_realm_subdomain_clears_user_realm_cache(self) -> None:
     """The main complicated thing about changing realm subdomains is
     updating the cache, and we start by populating the cache for
     Hamlet, and we end by checking the cache to ensure that his
     realm appears to be deactivated.  You can make this test fail
     by disabling cache.flush_realm()."""
     user = get_user_profile_by_email('*****@*****.**')
     realm = get_realm('zulip')
     do_change_realm_subdomain(realm, "newzulip")
     user = get_user_profile_by_email('*****@*****.**')
     self.assertEqual(user.realm.string_id, "newzulip")
     # This doesn't use a cache right now, but may later.
     self.assertIsNone(get_realm("zulip"))
Example #13
0
    def test_register_deactivated(self):
        """
        If you try to register for a deactivated realm, you get a clear error
        page.
        """
        realm = get_realm("zulip.com")
        realm.deactivated = True
        realm.save(update_fields=["deactivated"])

        result = self.register("test", "test")
        self.assertIn("has been deactivated", result.content.replace("\n", " "))

        with self.assertRaises(UserProfile.DoesNotExist):
            get_user_profile_by_email('*****@*****.**')
Example #14
0
    def test_mention_multiple(self):
        sender_user_profile = get_user_profile_by_email("*****@*****.**")
        hamlet = get_user_profile_by_email("*****@*****.**")
        cordelia = get_user_profile_by_email("*****@*****.**")
        msg = Message(sender=sender_user_profile, sending_client=get_client("test"))

        content = "@**King Hamlet** and @**cordelia**, check this out"
        self.assertEqual(msg.render_markdown(content),
                         '<p>'
                         '<span class="user-mention" '
                         'data-user-email="*****@*****.**">@King Hamlet</span> and '
                         '<span class="user-mention" '
                         'data-user-email="*****@*****.**">@Cordelia Lear</span>, '
                         'check this out</p>')
        self.assertEqual(msg.mentions_user_ids, set([hamlet.id, cordelia.id]))
Example #15
0
    def handle(self, **options):
        # type: (**Any) -> None
        if (
            options["string_id"] is None
            or options["streams"] is None
            or (options["users"] is None and options["all_users"] is None)
        ):
            self.print_help("./manage.py", "add_users_to_streams")
            exit(1)

        stream_names = set([stream.strip() for stream in options["streams"].split(",")])
        realm = get_realm_by_string_id(options["string_id"])

        if options["all_users"]:
            user_profiles = UserProfile.objects.filter(realm=realm)
        else:
            emails = set([email.strip() for email in options["users"].split(",")])
            user_profiles = []
            for email in emails:
                user_profiles.append(get_user_profile_by_email(email))

        for stream_name in set(stream_names):
            for user_profile in user_profiles:
                stream, _ = create_stream_if_needed(user_profile.realm, stream_name)
                _ignore, already_subscribed = bulk_add_subscriptions([stream], [user_profile])
                was_there_already = user_profile.id in {tup[0].id for tup in already_subscribed}
                print(
                    "%s %s to %s"
                    % ("Already subscribed" if was_there_already else "Subscribed", user_profile.email, stream_name)
                )
Example #16
0
    def authenticate(self, *args, **kwargs):
        # type: (*Any, **Any) -> Optional[UserProfile]
        return_data = kwargs.get('return_data', {})

        email_address = self.get_email_address(*args, **kwargs)
        if not email_address:
            return None

        try:
            user_profile = get_user_profile_by_email(email_address)
        except UserProfile.DoesNotExist:
            return_data["valid_attestation"] = True
            return None

        if not user_profile.is_active:
            return_data["inactive_user"] = True
            return None

        if user_profile.realm.deactivated:
            return_data["inactive_realm"] = True
            return None

        if not check_subdomain(kwargs.get("realm_subdomain"),
                               user_profile.realm.subdomain):
            return_data["invalid_subdomain"] = True
            return None

        return user_profile
Example #17
0
 def subscribe_to_stream(self, email, stream_name, realm=None):
     realm = get_realm(resolve_email_to_domain(email))
     stream = get_stream(stream_name, realm)
     if stream is None:
         stream, _ = create_stream_if_needed(realm, stream_name)
     user_profile = get_user_profile_by_email(email)
     do_add_subscription(user_profile, stream, no_log=True)
Example #18
0
    def send_mail(self, subject_template_name, email_template_name,
                  context, from_email, to_email, html_email_template_name=None):
        # type: (str, str, Dict[str, Any], str, str, str) -> None
        """
        Currently we don't support accounts in multiple subdomains using
        a single email address. We override this function so that we do
        not send a reset link to an email address if the reset attempt is
        done on the subdomain which does not match user.realm.subdomain.

        Once we start supporting accounts with the same email in
        multiple subdomains, we may be able to refactor this function.

        A second reason we override this function is so that we can send
        the mail through the functions in zerver.lib.send_email, to match
        how we send all other mail in the codebase.
        """
        user = get_user_profile_by_email(to_email)
        attempted_subdomain = get_subdomain(getattr(self, 'request'))
        context['attempted_realm'] = False
        if not check_subdomain(user.realm.subdomain, attempted_subdomain):
            context['attempted_realm'] = get_realm(attempted_subdomain)

        send_email('zerver/emails/password_reset', to_user_id=user.id,
                   from_name="Zulip Account Security",
                   from_address=FromAddress.NOREPLY, context=context)
Example #19
0
    def clean_username(self):
        # type: () -> str
        email = self.cleaned_data['username']
        try:
            user_profile = get_user_profile_by_email(email)
        except UserProfile.DoesNotExist:
            return email

        if user_profile.realm.deactivated:
            error_msg = u"""Sorry for the trouble, but %s has been deactivated.

Please contact %s to reactivate this group.""" % (
                user_profile.realm.name,
                FromAddress.SUPPORT)
            raise ValidationError(mark_safe(error_msg))

        if not user_profile.is_active and not user_profile.is_mirror_dummy:
            error_msg = (u"Sorry for the trouble, but your account has been "
                         u"deactivated. Please contact %s to reactivate "
                         u"it.") % (FromAddress.SUPPORT,)
            raise ValidationError(mark_safe(error_msg))

        if not check_subdomain(get_subdomain(self.request), user_profile.realm.subdomain):
            logging.warning("User %s attempted to password login to wrong subdomain %s" %
                            (user_profile.email, get_subdomain(self.request)))
            raise ValidationError(mark_safe(WRONG_SUBDOMAIN_ERROR))
        return email
Example #20
0
def enqueue_welcome_emails(email, name):
    sender = {'email': '*****@*****.**', 'name': 'Waseem Daher'}
    if settings.VOYAGER:
        sender = {'email': settings.ZULIP_ADMINISTRATOR, 'name': 'Zulip'}

    user_profile = get_user_profile_by_email(email)
    unsubscribe_link = one_click_unsubscribe_link(user_profile, "welcome")

    template_payload = {'name': name,
                        'not_voyager': not settings.VOYAGER,
                        'external_host': settings.EXTERNAL_HOST,
                        'unsubscribe_link': unsubscribe_link}

    #Send day 1 email
    send_local_email_template_with_delay([{'email': email, 'name': name}],
                                         "zerver/emails/followup/day1",
                                         template_payload,
                                         datetime.timedelta(hours=1),
                                         tags=["followup-emails"],
                                         sender=sender)
    #Send day 2 email
    tomorrow = datetime.datetime.utcnow() + datetime.timedelta(hours=24)
    # 11 AM EDT
    tomorrow_morning = datetime.datetime(tomorrow.year, tomorrow.month, tomorrow.day, 15, 0)
    assert(datetime.datetime.utcnow() < tomorrow_morning)
    send_local_email_template_with_delay([{'email': email, 'name': name}],
                                         "zerver/emails/followup/day2",
                                         template_payload,
                                         tomorrow_morning - datetime.datetime.utcnow(),
                                         tags=["followup-emails"],
                                         sender=sender)
Example #21
0
File: users.py Project: zulip/zulip
def update_user_backend(request, user_profile, email,
                        full_name=REQ(default="", validator=check_string),
                        is_admin=REQ(default=None, validator=check_bool)):
    # type: (HttpRequest, UserProfile, text_type, Optional[text_type], Optional[bool]) -> HttpResponse
    try:
        target = get_user_profile_by_email(email)
    except UserProfile.DoesNotExist:
        return json_error(_('No such user'))

    if not user_profile.can_admin_user(target):
        return json_error(_('Insufficient permission'))

    if is_admin is not None:
        if not is_admin and check_last_admin(user_profile):
            return json_error(_('Cannot remove the only organization administrator'))
        do_change_is_admin(target, is_admin)

    if (full_name is not None and target.full_name != full_name and
            full_name.strip() != ""):
        # We don't respect `name_changes_disabled` here because the request
        # is on behalf of the administrator.
        new_full_name = full_name.strip()
        if len(new_full_name) > UserProfile.MAX_NAME_LENGTH:
            return json_error(_("Name too long!"))
        do_change_full_name(target, new_full_name)

    return json_success()
Example #22
0
def enqueue_welcome_emails(email, name):
    # type: (Text, Text) -> None
    from zerver.context_processors import common_context
    if settings.WELCOME_EMAIL_SENDER is not None:
        sender = settings.WELCOME_EMAIL_SENDER # type: Dict[str, Text]
    else:
        sender = {'email': settings.ZULIP_ADMINISTRATOR, 'name': 'Zulip'}

    user_profile = get_user_profile_by_email(email)
    unsubscribe_link = one_click_unsubscribe_link(user_profile, "welcome")
    template_payload = common_context(user_profile)
    template_payload.update({
        'verbose_support_offers': settings.VERBOSE_SUPPORT_OFFERS,
        'unsubscribe_link': unsubscribe_link
    })

    # Send day 1 email
    send_local_email_template_with_delay([{'email': email, 'name': name}],
                                         "zerver/emails/followup/day1",
                                         template_payload,
                                         datetime.timedelta(hours=1),
                                         tags=["followup-emails"],
                                         sender=sender)
    # Send day 2 email
    send_local_email_template_with_delay([{'email': email, 'name': name}],
                                         "zerver/emails/followup/day2",
                                         template_payload,
                                         datetime.timedelta(days=1),
                                         tags=["followup-emails"],
                                         sender=sender)
Example #23
0
def enqueue_welcome_emails(email, name):
    # type: (text_type, text_type) -> None
    if settings.WELCOME_EMAIL_SENDER is not None:
        sender = settings.WELCOME_EMAIL_SENDER # type: Dict[str, text_type]
    else:
        sender = {'email': settings.ZULIP_ADMINISTRATOR, 'name': 'Zulip'}

    user_profile = get_user_profile_by_email(email)
    unsubscribe_link = one_click_unsubscribe_link(user_profile, "welcome")

    template_payload = {'name': name,
                        'verbose_support_offers': settings.VERBOSE_SUPPORT_OFFERS,
                        'external_host': settings.EXTERNAL_HOST,
                        'external_uri_scheme': settings.EXTERNAL_URI_SCHEME,
                        'server_uri': settings.SERVER_URI,
                        'realm_uri': user_profile.realm.uri,
                        'unsubscribe_link': unsubscribe_link}

    # Send day 1 email
    send_local_email_template_with_delay([{'email': email, 'name': name}],
                                         "zerver/emails/followup/day1",
                                         template_payload,
                                         datetime.timedelta(hours=1),
                                         tags=["followup-emails"],
                                         sender=sender)
    # Send day 2 email
    send_local_email_template_with_delay([{'email': email, 'name': name}],
                                         "zerver/emails/followup/day2",
                                         template_payload,
                                         datetime.timedelta(days=1),
                                         tags=["followup-emails"],
                                         sender=sender)
Example #24
0
    def by_pm_with(self, query, operand, maybe_negate):
        # type: (Query, str, ConditionTransform) -> Query
        if ',' in operand:
            # Huddle
            try:
                emails = [e.strip() for e in operand.split(',')]
                recipient = recipient_for_emails(emails, False,
                                                 self.user_profile, self.user_profile)
            except ValidationError:
                raise BadNarrowOperator('unknown recipient ' + operand)
            cond = column("recipient_id") == recipient.id
            return query.where(maybe_negate(cond))
        else:
            # Personal message
            self_recipient = get_recipient(Recipient.PERSONAL, type_id=self.user_profile.id)
            if operand == self.user_profile.email:
                # Personals with self
                cond = and_(column("sender_id") == self.user_profile.id,
                            column("recipient_id") == self_recipient.id)
                return query.where(maybe_negate(cond))

            # Personals with other user; include both directions.
            try:
                narrow_profile = get_user_profile_by_email(operand)
            except UserProfile.DoesNotExist:
                raise BadNarrowOperator('unknown user ' + operand)

            narrow_recipient = get_recipient(Recipient.PERSONAL, narrow_profile.id)
            cond = or_(and_(column("sender_id") == narrow_profile.id,
                            column("recipient_id") == self_recipient.id),
                       and_(column("sender_id") == self.user_profile.id,
                            column("recipient_id") == narrow_recipient.id))
            return query.where(maybe_negate(cond))
Example #25
0
    def test_digest_unsubscribe(self):
        # type: () -> None
        """
        We provide one-click unsubscribe links in digest e-mails that you can
        click even when logged out to stop receiving them.

        Unsubscribing from these emails also dequeues any digest email jobs that
        have been queued.
        """
        email = "*****@*****.**"
        user_profile = get_user_profile_by_email("*****@*****.**")
        self.assertTrue(user_profile.enable_digest_emails)

        # Enqueue a fake digest email.
        send_digest_email(user_profile, "", "")
        self.assertEqual(1, len(ScheduledJob.objects.filter(
                    type=ScheduledJob.EMAIL, filter_string__iexact=email)))

        # Simulate unsubscribing from digest e-mails.
        unsubscribe_link = one_click_unsubscribe_link(user_profile, "digest")
        result = self.client_get(urllib.parse.urlparse(unsubscribe_link).path)

        # The setting is toggled off, and scheduled jobs have been removed.
        self.assertEqual(result.status_code, 200)
        # Circumvent user_profile caching.
        user_profile = UserProfile.objects.get(email="*****@*****.**")
        self.assertFalse(user_profile.enable_digest_emails)
        self.assertEqual(0, len(ScheduledJob.objects.filter(
                type=ScheduledJob.EMAIL, filter_string__iexact=email)))
Example #26
0
def extract_and_upload_attachments(message, realm):
    # type: (message.Message, Realm) -> text_type
    user_profile = get_user_profile_by_email(settings.EMAIL_GATEWAY_BOT)
    attachment_links = []

    payload = message.get_payload()
    if not isinstance(payload, list):
        # This is not a multipart message, so it can't contain attachments.
        return ""

    for part in payload:
        content_type = part.get_content_type()
        filename = part.get_filename()
        if filename:
            attachment = part.get_payload(decode=True)
            if isinstance(attachment, binary_type):
                s3_url = upload_message_image(filename, content_type,
                                              attachment,
                                              user_profile,
                                              target_realm=realm)
                formatted_link = u"[%s](%s)" % (filename, s3_url)
                attachment_links.append(formatted_link)
            else:
                logger.warning("Payload is not bytes (invalid attachment %s in message from %s)." %
                               (filename, message.get("From")))

    return u"\n".join(attachment_links)
Example #27
0
def create_mirrored_message_users(request, user_profile, recipients):
    # type: (HttpResponse, UserProfile, Iterable[Text]) -> Tuple[bool, Optional[UserProfile]]
    if "sender" not in request.POST:
        return (False, None)

    sender_email = request.POST["sender"].strip().lower()
    referenced_users = set([sender_email])
    if request.POST['type'] == 'private':
        for email in recipients:
            referenced_users.add(email.lower())

    if request.client.name == "zephyr_mirror":
        user_check = same_realm_zephyr_user
        fullname_function = compute_mit_user_fullname
    elif request.client.name == "irc_mirror":
        user_check = same_realm_irc_user
        fullname_function = compute_irc_user_fullname
    elif request.client.name in ("jabber_mirror", "JabberMirror"):
        user_check = same_realm_jabber_user
        fullname_function = compute_jabber_user_fullname
    else:
        # Unrecognized mirroring client
        return (False, None)

    for email in referenced_users:
        # Check that all referenced users are in our realm:
        if not user_check(user_profile, email):
            return (False, None)

    # Create users for the referenced users, if needed.
    for email in referenced_users:
        create_mirror_user_if_needed(user_profile.realm, email, fullname_function)

    sender = get_user_profile_by_email(sender_email)
    return (True, sender)
Example #28
0
    def test_receive_stream_email_messages_success(self):

        # build dummy messages for stream
        # test valid incoming stream message is processed properly
        self.login("*****@*****.**")
        user_profile = get_user_profile_by_email("*****@*****.**")
        self.subscribe_to_stream(user_profile.email, "Denmark")
        stream = get_stream("Denmark", user_profile.realm)

        stream_to_address = encode_email_address(stream)

        incoming_valid_message = MIMEText('TestStreamEmailMessages Body')

        incoming_valid_message['Subject'] = 'TestStreamEmailMessages Subject'
        incoming_valid_message['From'] = "*****@*****.**"
        incoming_valid_message['To'] = stream_to_address
        incoming_valid_message['Reply-to'] = "*****@*****.**"

        process_message(incoming_valid_message)

        # Hamlet is subscribed to this stream so should see the email message from Othello.
        message = most_recent_message(user_profile)

        self.assertEqual(message.content, "TestStreamEmailMessages Body")
        self.assertEqual(get_display_recipient(message.recipient), stream.name)
        self.assertEqual(message.subject, incoming_valid_message['Subject'])
    def handle(self, **options):
        # type: (*Any, **Any) -> None
        if options["domain"] is None or options["stream"] is None or \
                (options["users"] is None and options["all_users"] is None):
            self.print_help("./manage.py", "remove_users_from_stream")
            exit(1)

        realm = get_realm(options["domain"])
        stream_name = options["stream"].strip()
        stream = get_stream(stream_name, realm)

        if options["all_users"]:
            user_profiles = UserProfile.objects.filter(realm=realm)
        else:
            emails = set([email.strip() for email in options["users"].split(",")])
            user_profiles = []
            for email in emails:
                user_profiles.append(get_user_profile_by_email(email))

        result = bulk_remove_subscriptions(user_profiles, [stream])
        not_subscribed = result[1]
        not_subscribed_users = {tup[0] for tup in not_subscribed}

        for user_profile in user_profiles:
            if user_profile in not_subscribed_users:
                print("%s was not subscribed" % (user_profile.email,))
            else:
                print("Removed %s from %s" % (user_profile.email, stream_name))
Example #30
0
    def test_receive_stream_email_messages_empty_body(self):

        # build dummy messages for stream
        # test message with empty body is not sent
        self.login("*****@*****.**")
        user_profile = get_user_profile_by_email("*****@*****.**")
        self.subscribe_to_stream(user_profile.email, "Denmark")
        stream = get_stream("Denmark", user_profile.realm)

        stream_to_address = encode_email_address(stream)
        headers = {}
        headers['Reply-To'] = '*****@*****.**'

        # empty body
        incoming_valid_message = MIMEText('')

        incoming_valid_message['Subject'] = 'TestStreamEmailMessages Subject'
        incoming_valid_message['From'] = "*****@*****.**"
        incoming_valid_message['To'] = stream_to_address
        incoming_valid_message['Reply-to'] = "*****@*****.**"

        exception_message = ""
        debug_info = {}

        # process_message eats the exception & logs an error which can't be parsed here
        # so calling process_stream_message directly
        try:
            process_stream_message(incoming_valid_message['To'],
                incoming_valid_message['Subject'],
                incoming_valid_message,
                debug_info)
        except ZulipEmailForwardError as e:
            # empty body throws exception
            exception_message = e.message
        self.assertEqual(exception_message, "Unable to find plaintext or HTML message body")
Example #31
0
def common_get_active_user_by_email(email, return_data=None):
    # type: (text_type, Optional[Dict[str, Any]]) -> Optional[UserProfile]
    try:
        user_profile = get_user_profile_by_email(email)
    except UserProfile.DoesNotExist:
        return None
    if not user_profile.is_active:
        if return_data is not None:
            return_data['inactive_user'] = True
        return None
    if user_profile.realm.deactivated:
        if return_data is not None:
            return_data['inactive_realm'] = True
        return None
    return user_profile
Example #32
0
    def test_invite_user_signup_initial_history(self):
        """
        Test that a new user invited to a stream receives some initial
        history but only from public streams.
        """
        self.login("*****@*****.**")
        user_profile = get_user_profile_by_email("*****@*****.**")
        private_stream_name = "Secret"
        (stream, _) = create_stream_if_needed(user_profile.realm, private_stream_name, invite_only=True)
        do_add_subscription(user_profile, stream)
        public_msg_id = self.send_message("*****@*****.**", "Denmark", Recipient.STREAM,
                                          "Public topic", "Public message")
        secret_msg_id = self.send_message("*****@*****.**", private_stream_name, Recipient.STREAM,
                                          "Secret topic", "Secret message")
        invitee = "*****@*****.**"
        self.assert_json_success(self.invite(invitee, [private_stream_name, "Denmark"]))
        self.assertTrue(find_key_by_email(invitee))

        self.submit_reg_form_for_user("alice-test", "password")
        invitee_profile = get_user_profile_by_email(invitee)
        invitee_msg_ids = [um.message_id for um in
                           UserMessage.objects.filter(user_profile=invitee_profile)]
        self.assertTrue(public_msg_id in invitee_msg_ids)
        self.assertFalse(secret_msg_id in invitee_msg_ids)
Example #33
0
    def send_message(self, sender_name, recipient_list, message_type,
                     content="test content", subject="test", **kwargs):
        sender = get_user_profile_by_email(sender_name)
        if message_type == Recipient.PERSONAL:
            message_type_name = "private"
        else:
            message_type_name = "stream"
        if isinstance(recipient_list, six.string_types):
            recipient_list = [recipient_list]
        (sending_client, _) = Client.objects.get_or_create(name="test suite")

        return check_send_message(
            sender, sending_client, message_type_name, recipient_list, subject,
            content, forged=False, forged_timestamp=None,
            forwarder_user_profile=sender, realm=sender.realm, **kwargs)
Example #34
0
def create_user_backend(request, user_profile, email=REQ(), password=REQ(),
                        full_name_raw=REQ("full_name"), short_name=REQ()):
    # type: (HttpRequest, UserProfile, Text, Text, Text, Text) -> HttpResponse
    full_name = check_full_name(full_name_raw)
    form = CreateUserForm({'full_name': full_name, 'email': email})
    if not form.is_valid():
        return json_error(_('Bad name or username'))

    # Check that the new user's email address belongs to the admin's realm
    # (Since this is an admin API, we don't require the user to have been
    # invited first.)
    realm = user_profile.realm
    if not email_allowed_for_realm(email, user_profile.realm):
        return json_error(_("Email '%(email)s' does not belong to domain '%(domain)s'") %
                          {'email': email, 'domain': realm.domain})

    try:
        get_user_profile_by_email(email)
        return json_error(_("Email '%s' already in use") % (email,))
    except UserProfile.DoesNotExist:
        pass

    do_create_user(email, password, realm, full_name, short_name)
    return json_success()
Example #35
0
    def clean_username(self):
        email = self.cleaned_data['username']
        try:
            user_profile = get_user_profile_by_email(email)
        except UserProfile.DoesNotExist:
            return email

        if user_profile.realm.deactivated:
            error_msg = u"""Sorry for the trouble, but %s has been deactivated.

Please contact %s to reactivate this group.""" % (user_profile.realm.name,
                                                  settings.ZULIP_ADMINISTRATOR)
            raise ValidationError(mark_safe(error_msg))

        return email
Example #36
0
    def ensure_medium_avatar_image(self, email):
        # type: (Text) -> None
        user_profile = get_user_profile_by_email(email)
        file_path = user_avatar_path(user_profile)

        output_path = os.path.join(settings.LOCAL_UPLOADS_DIR, "avatars",
                                   file_path + "-medium.png")
        if os.path.isfile(output_path):
            return

        image_path = os.path.join(settings.LOCAL_UPLOADS_DIR, "avatars",
                                  file_path + ".original")
        image_data = open(image_path, "rb").read()
        resized_medium = resize_avatar(image_data, MEDIUM_AVATAR_SIZE)
        write_local_file('avatars', file_path + '-medium.png', resized_medium)
Example #37
0
    def ensure_medium_avatar_image(self, email):
        # type: (Text) -> None
        user_profile = get_user_profile_by_email(email)
        email_hash = user_avatar_hash(email)
        s3_file_name = email_hash

        bucket_name = settings.S3_AVATAR_BUCKET
        conn = S3Connection(settings.S3_KEY, settings.S3_SECRET_KEY)
        bucket = get_bucket(conn, force_str(bucket_name))
        key = bucket.get_key(email_hash)
        image_data = key.get_contents_as_string()

        resized_medium = resize_avatar(image_data, MEDIUM_AVATAR_SIZE)
        upload_image_to_s3(bucket_name, s3_file_name + "-medium.png",
                           "image/png", user_profile, resized_medium)
Example #38
0
def regenerate_bot_api_key(request, user_profile, email):
    # type: (HttpRequest, UserProfile, Text) -> HttpResponse
    try:
        bot = get_user_profile_by_email(email)
    except:
        return json_error(_('No such user'))

    if not user_profile.can_admin_user(bot):
        return json_error(_('Insufficient permission'))

    do_regenerate_api_key(bot)
    json_result = dict(
        api_key = bot.api_key
    )
    return json_success(json_result)
Example #39
0
    def authenticate(self, remote_user):
        if not remote_user:
            return

        email = remote_user_to_email(remote_user)

        try:
            user_profile = get_user_profile_by_email(email)
        except UserProfile.DoesNotExist:
            return None

        if user_profile.is_mirror_dummy:
            # mirror dummies can not login, but they can convert to real users
            return None

        return user_profile
Example #40
0
    def authenticate(self, username=None, password=None):
        """ Authenticate a user based on email address as the user name. """
        if username is None or password is None:
            # Return immediately.  Otherwise we will look for a SQL row with
            # NULL username.  While that's probably harmless, it's needless
            # exposure.
            return None

        try:
            user_profile = get_user_profile_by_email(username)
            if not password_auth_enabled(user_profile.realm):
                return None
            if user_profile.check_password(password):
                return user_profile
        except UserProfile.DoesNotExist:
            return None
Example #41
0
    def handle(self, *args, **options):
        # type: (*Any, **str) -> None
        data_file = options['data_file']
        with open(data_file, "r") as f:
            for line in f:
                email, new_name = line.strip().split(",", 1)

                try:
                    user_profile = get_user_profile_by_email(email)
                    old_name = user_profile.full_name
                    print("%s: %s -> %s" % (email, old_name, new_name))
                    do_change_full_name(user_profile, new_name, None)
                except UserProfile.DoesNotExist:
                    print(
                        "* E-mail %s doesn't exist in the system, skipping." %
                        (email, ))
Example #42
0
def avatar(request, email):
    # type: (HttpRequest, str) -> HttpResponse
    try:
        user_profile = get_user_profile_by_email(email)
        avatar_source = user_profile.avatar_source
    except UserProfile.DoesNotExist:
        avatar_source = 'G'
    url = get_avatar_url(avatar_source, email)

    # We can rely on the url already having query parameters. Because
    # our templates depend on being able to use the ampersand to
    # add query parameters to our url, get_avatar_url does '?x=x'
    # hacks to prevent us from having to jump through decode/encode hoops.
    assert '?' in url
    url += '&' + request.META['QUERY_STRING']
    return redirect(url)
Example #43
0
def update_user_backend(request,
                        user_profile,
                        email,
                        is_admin=REQ(default=None, validator=check_bool)):
    # type: (HttpRequest, UserProfile, text_type, Optional[bool]) -> HttpResponse
    try:
        target = get_user_profile_by_email(email)
    except UserProfile.DoesNotExist:
        return json_error(_('No such user'))

    if not user_profile.can_admin_user(target):
        return json_error(_('Insufficient permission'))

    if is_admin is not None:
        do_change_is_admin(target, is_admin)
    return json_success({})
Example #44
0
    def test_realm_patterns(self):
        RealmFilter(
            realm=get_realm('zulip.com'),
            pattern=r"#(?P<id>[0-9]{2,8})",
            url_format_string=r"https://trac.zulip.net/ticket/%(id)s").save()
        msg = Message(sender=get_user_profile_by_email("*****@*****.**"))

        content = "We should fix #224 and #115, but not issue#124 or #1124z or [trac #15](https://trac.zulip.net/ticket/16) today."
        converted = bugdown.convert(content,
                                    realm_domain='zulip.com',
                                    message=msg)

        self.assertEqual(
            converted,
            '<p>We should fix <a href="https://trac.zulip.net/ticket/224" target="_blank" title="https://trac.zulip.net/ticket/224">#224</a> and <a href="https://trac.zulip.net/ticket/115" target="_blank" title="https://trac.zulip.net/ticket/115">#115</a>, but not issue#124 or #1124z or <a href="https://trac.zulip.net/ticket/16" target="_blank" title="https://trac.zulip.net/ticket/16">trac #15</a> today.</p>'
        )
Example #45
0
def patch_bot_backend(request,
                      user_profile,
                      email,
                      full_name=REQ(default=None),
                      default_sending_stream=REQ(default=None),
                      default_events_register_stream=REQ(default=None),
                      default_all_public_streams=REQ(default=None,
                                                     validator=check_bool)):
    # type: (HttpRequest, UserProfile, text_type, Optional[text_type], Optional[text_type], Optional[text_type], Optional[bool]) -> HttpResponse
    try:
        bot = get_user_profile_by_email(email)
    except:
        return json_error(_('No such user'))

    if not user_profile.can_admin_user(bot):
        return json_error(_('Insufficient permission'))

    if full_name is not None:
        do_change_full_name(bot, full_name)
    if default_sending_stream is not None:
        stream = stream_or_none(default_sending_stream, bot.realm)
        do_change_default_sending_stream(bot, stream)
    if default_events_register_stream is not None:
        stream = stream_or_none(default_events_register_stream, bot.realm)
        do_change_default_events_register_stream(bot, stream)
    if default_all_public_streams is not None:
        do_change_default_all_public_streams(bot, default_all_public_streams)

    if len(request.FILES) == 0:
        pass
    elif len(request.FILES) == 1:
        user_file = list(request.FILES.values())[0]
        upload_avatar_image(user_file, user_profile, bot.email)
        avatar_source = UserProfile.AVATAR_FROM_USER
        do_change_avatar_source(bot, avatar_source)
    else:
        return json_error(_("You may only upload one file at a time"))

    json_result = dict(
        full_name=bot.full_name,
        avatar_url=avatar_url(bot),
        default_sending_stream=get_stream_name(bot.default_sending_stream),
        default_events_register_stream=get_stream_name(
            bot.default_events_register_stream),
        default_all_public_streams=bot.default_all_public_streams,
    )
    return json_success(json_result)
Example #46
0
    def send_stream_message(self,
                            sender_email,
                            stream_name,
                            content=u"test content",
                            topic_name=u"test"):
        # type: (Text, Text, Text, Text) -> int
        sender = get_user_profile_by_email(sender_email)

        (sending_client, _) = Client.objects.get_or_create(name="test suite")

        return check_send_stream_message(
            sender=sender,
            client=sending_client,
            stream_name=stream_name,
            topic=topic_name,
            body=content,
        )
Example #47
0
def enqueue_welcome_emails(email, name):
    # type: (text_type, text_type) -> None
    if settings.WELCOME_EMAIL_SENDER is not None:
        sender = settings.WELCOME_EMAIL_SENDER  # type: Dict[str, text_type]
    else:
        sender = {'email': settings.ZULIP_ADMINISTRATOR, 'name': 'Zulip'}

    user_profile = get_user_profile_by_email(email)
    unsubscribe_link = one_click_unsubscribe_link(user_profile, "welcome")

    template_payload = {
        'name': name,
        'verbose_support_offers': settings.VERBOSE_SUPPORT_OFFERS,
        'external_host': settings.EXTERNAL_HOST,
        'external_uri_scheme': settings.EXTERNAL_URI_SCHEME,
        'server_uri': settings.SERVER_URI,
        'realm_uri': user_profile.realm.uri,
        'unsubscribe_link': unsubscribe_link
    }

    # Send day 1 email
    send_local_email_template_with_delay([{
        'email': email,
        'name': name
    }],
                                         "zerver/emails/followup/day1",
                                         template_payload,
                                         datetime.timedelta(hours=1),
                                         tags=["followup-emails"],
                                         sender=sender)
    # Send day 2 email
    tomorrow = datetime.datetime.utcnow() + datetime.timedelta(hours=24)
    # 11 AM EDT
    tomorrow_morning = datetime.datetime(tomorrow.year, tomorrow.month,
                                         tomorrow.day, 15, 0)
    assert (datetime.datetime.utcnow() < tomorrow_morning)
    send_local_email_template_with_delay([{
        'email': email,
        'name': name
    }],
                                         "zerver/emails/followup/day2",
                                         template_payload,
                                         tomorrow_morning -
                                         datetime.datetime.utcnow(),
                                         tags=["followup-emails"],
                                         sender=sender)
Example #48
0
    def test_invite_with_non_ascii_streams(self):
        """
        Inviting someone to streams with non-ASCII characters succeeds.
        """
        self.login("*****@*****.**")
        invitee = "*****@*****.**"

        stream_name = u"hümbüǵ"
        realm = get_realm("zulip.com")
        stream, _ = create_stream_if_needed(realm, stream_name)

        # Make sure we're subscribed before inviting someone.
        do_add_subscription(get_user_profile_by_email("*****@*****.**"),
                            stream,
                            no_log=True)

        self.assert_json_success(self.invite(invitee, [stream_name]))
Example #49
0
    def consume(self, data):
        invitee = get_prereg_user_by_email(data["email"])
        referrer = get_user_profile_by_email(data["referrer_email"])
        do_send_confirmation_email(invitee, referrer)

        # queue invitation reminder for two days from now.
        link = Confirmation.objects.get_link_for_object(invitee)
        send_local_email_template_with_delay([{'email': data["email"], 'name': ""}],
                                             "zerver/emails/invitation/invitation_reminder_email",
                                             {'activate_url': link,
                                              'referrer': referrer,
                                              'verbose_support_offers': settings.VERBOSE_SUPPORT_OFFERS,
                                              'external_host': settings.EXTERNAL_HOST,
                                              'support_email': settings.ZULIP_ADMINISTRATOR},
                                             datetime.timedelta(days=2),
                                             tags=["invitation-reminders"],
                                             sender={'email': settings.ZULIP_ADMINISTRATOR, 'name': 'Zulip'})
Example #50
0
 def handle(self, *args, **options):
     # type: (*Any, **str) -> None
     if options["to"]:
         users = [get_user_profile_by_email(options["to"])]
     elif options["realm"]:
         realm = get_realm(options["realm"])
         users = UserProfile.objects.filter(realm=realm,
                                            is_active=True,
                                            is_bot=False,
                                            is_mirror_dummy=False)
     elif options["server"] == "YES":
         users = UserProfile.objects.filter(is_active=True,
                                            is_bot=False,
                                            is_mirror_dummy=False)
     else:
         raise RuntimeError("Missing arguments")
     self.send(users)
Example #51
0
    def get_or_create_user(self, username, ldap_user):
        try:
            return get_user_profile_by_email(username), False
        except UserProfile.DoesNotExist:
            domain = resolve_email_to_domain(username)
            realm = get_realm(domain)

            full_name_attr = settings.AUTH_LDAP_USER_ATTR_MAP["full_name"]
            short_name = full_name = ldap_user.attrs[full_name_attr][0]
            if "short_name" in settings.AUTH_LDAP_USER_ATTR_MAP:
                short_name_attr = settings.AUTH_LDAP_USER_ATTR_MAP[
                    "short_name"]
                short_name = ldap_user.attrs[short_name_attr][0]

            user_profile = do_create_user(username, None, realm, full_name,
                                          short_name)
            return user_profile, False
Example #52
0
    def test_realm_emoji(self):
        def emoji_img(name, url):
            return '<img alt="%s" class="emoji" src="%s" title="%s">' % (
                name, url, name)

        zulip_realm = get_realm('zulip.com')
        url = "https://zulip.com/test_realm_emoji.png"
        do_add_realm_emoji(zulip_realm, "test", url)

        # Needs to mock an actual message because that's how bugdown obtains the realm
        msg = Message(sender=get_user_profile_by_email("*****@*****.**"))
        converted = bugdown.convert(":test:", "zulip.com", msg)
        self.assertEqual(converted, '<p>%s</p>' % (emoji_img(':test:', url)))

        do_remove_realm_emoji(zulip_realm, 'test')
        converted = bugdown.convert(":test:", "zulip.com", msg)
        self.assertEqual(converted, '<p>:test:</p>')
Example #53
0
    def handle(self, *args, **options):
        # type: (*Any, **Any) -> None
        if not options["flag"] or not options["op"] or not options["email"]:
            print("Please specify an operation, a flag and an email")
            exit(1)

        op = options['op']
        flag = getattr(UserMessage.flags, options['flag'])
        all_until = options['all_until']
        email = options['email']

        user_profile = get_user_profile_by_email(email)

        if all_until:
            filt = models.Q(id__lte=all_until)
        else:
            filt = models.Q(message__id__in=[
                mid.strip() for mid in sys.stdin.read().split(',')
            ])
        mids = [
            m.id for m in UserMessage.objects.filter(
                filt, user_profile=user_profile).order_by('-id')
        ]

        if options["for_real"]:
            sys.stdin.close()
            sys.stdout.close()
            sys.stderr.close()

        def do_update(batch):
            # type: (Iterable[int]) -> None
            msgs = UserMessage.objects.filter(id__in=batch)
            if op == 'add':
                msgs.update(flags=models.F('flags').bitor(flag))
            elif op == 'remove':
                msgs.update(flags=models.F('flags').bitand(~flag))

        if not options["for_real"]:
            logging.info("Updating %s by %s %s" % (mids, op, flag))
            logging.info(
                "Dry run completed. Run with --for-real to change message flags."
            )
            exit(1)

        utils.run_in_batches(mids, 400, do_update, sleep_time=3)
        exit(0)
Example #54
0
def enqueue_welcome_emails(email, name):
    # type: (text_type, text_type) -> None
    sender = {
        'email': '*****@*****.**',
        'name': 'Waseem Daher'
    }  # type: Dict[str, text_type]
    if settings.VOYAGER:
        sender = {'email': settings.ZULIP_ADMINISTRATOR, 'name': 'Zulip'}

    user_profile = get_user_profile_by_email(email)
    unsubscribe_link = one_click_unsubscribe_link(user_profile, "welcome")

    template_payload = {
        'name': name,
        'not_voyager': not settings.VOYAGER,
        'external_host': settings.EXTERNAL_HOST,
        'unsubscribe_link': unsubscribe_link
    }

    # Send day 1 email
    send_local_email_template_with_delay([{
        'email': email,
        'name': name
    }],
                                         "zerver/emails/followup/day1",
                                         template_payload,
                                         datetime.timedelta(hours=1),
                                         tags=["followup-emails"],
                                         sender=sender)
    # Send day 2 email
    tomorrow = datetime.datetime.utcnow() + datetime.timedelta(hours=24)
    # 11 AM EDT
    tomorrow_morning = datetime.datetime(tomorrow.year, tomorrow.month,
                                         tomorrow.day, 15, 0)
    assert (datetime.datetime.utcnow() < tomorrow_morning)
    send_local_email_template_with_delay([{
        'email': email,
        'name': name
    }],
                                         "zerver/emails/followup/day2",
                                         template_payload,
                                         tomorrow_morning -
                                         datetime.datetime.utcnow(),
                                         tags=["followup-emails"],
                                         sender=sender)
Example #55
0
    def test_missedmessage_unsubscribe(self):
        """
        We provide one-click unsubscribe links in missed message
        e-mails that you can click even when logged out to update your
        email notification settings.
        """
        user_profile = get_user_profile_by_email("*****@*****.**")
        user_profile.enable_offline_email_notifications = True
        user_profile.save()

        unsubscribe_link = one_click_unsubscribe_link(user_profile,
                                                      "missed_messages")
        result = self.client.get(urlparse(unsubscribe_link).path)

        self.assertEqual(result.status_code, 200)
        # Circumvent user_profile caching.
        user_profile = UserProfile.objects.get(email="*****@*****.**")
        self.assertFalse(user_profile.enable_offline_email_notifications)
Example #56
0
    def test_non_ascii_login(self):
        """
        You can log in even if your password contain non-ASCII characters.
        """
        email = "*****@*****.**"
        password = u"hümbüǵ"

        # Registering succeeds.
        self.register("test", password)
        user_profile = get_user_profile_by_email(email)
        self.assertEqual(get_session_dict_user(self.client.session), user_profile.id)
        self.client.post('/accounts/logout/')
        self.assertIsNone(get_session_dict_user(self.client.session))

        # Logging in succeeds.
        self.client.post('/accounts/logout/')
        self.login(email, password)
        self.assertEqual(get_session_dict_user(self.client.session), user_profile.id)
Example #57
0
    def api_auth(self, identifier):
        # type: (Text) -> Dict[str, Text]
        """
        identifier: Can be an email or a remote server uuid.
        """
        if identifier in API_KEYS:
            api_key = API_KEYS[identifier]
        else:
            if is_remote_server(identifier):
                api_key = get_remote_server_by_uuid(identifier).api_key
            else:
                api_key = get_user_profile_by_email(identifier).api_key
            API_KEYS[identifier] = api_key

        credentials = u"%s:%s" % (identifier, api_key)
        return {
            'HTTP_AUTHORIZATION': u'Basic ' + base64.b64encode(credentials.encode('utf-8')).decode('utf-8')
        }
Example #58
0
    def send_message(self, sender_name, raw_recipients, message_type,
                     content=u"test content", subject=u"test", **kwargs):
        # type: (text_type, Union[text_type, List[text_type]], int, text_type, text_type, **Any) -> int
        sender = get_user_profile_by_email(sender_name)
        if message_type == Recipient.PERSONAL:
            message_type_name = "private"
        else:
            message_type_name = "stream"
        if isinstance(raw_recipients, six.string_types):
            recipient_list = [raw_recipients]
        else:
            recipient_list = raw_recipients
        (sending_client, _) = Client.objects.get_or_create(name="test suite")

        return check_send_message(
            sender, sending_client, message_type_name, recipient_list, subject,
            content, forged=False, forged_timestamp=None,
            forwarder_user_profile=sender, realm=sender.realm, **kwargs)
Example #59
0
def api_beeminder_webhook(
    request: HttpRequest,
    user_profile: UserProfile,
    payload: Dict[str, Any] = REQ(argument_type='body'),
    stream: Text = REQ(default="beeminder"),
    email: str = REQ(default='*****@*****.**'),
    topic: Text = REQ(default='beekeeper')
) -> HttpResponse:

    secret = payload["goal"]["secret"]
    goal_name = payload["goal"]["slug"]
    losedate = payload["goal"]["losedate"]
    limsum = payload["goal"]["limsum"]
    pledge = payload["goal"]["pledge"]
    time_remain = (losedate - current_time) / 3600  # time in hours
    # To show user's probable reaction by looking at pledge amount
    if pledge > 0:
        expression = ':worried:'
    else:
        expression = ':relieved:'

    if not secret:
        # In this case notifications will be sent to stream

        name = get_user_name(email)
        body = u"Hello **{}**! I am the Beeminder bot! :octopus: \n You are going to derail \
        from goal **{}** in **{:0.1f} hours** \n You need **{}** to avoid derailing \n * Pledge: **{}$** {}"

        body = body.format(name, goal_name, time_remain, limsum, pledge,
                           expression)
        check_send_stream_message(user_profile, request.client, stream, topic,
                                  body)
        return json_success()

    else:
        # In this case PM will be sent to user
        p = get_user_profile_by_email(email)
        body = u"I am the Beeminder bot! :octopus: \n You are going to derail from \
        goal **{}** in **{:0.1f} hours** \n You need **{}** to avoid derailing \n * Pledge: **{}$**{}"

        body = body.format(goal_name, time_remain, limsum, pledge, expression)
        check_send_private_message(user_profile, request.client, p, body)
        return json_success()
Example #60
0
    def handle(self, *args, **options):
        try:
            user_profile = get_user_profile_by_email(options["email"])
        except UserProfile.DoesNotExist:
            raise CommandError("No such user.")

        output_dir = options["output_dir"]
        if output_dir is None:
            output_dir = tempfile.mkdtemp(prefix="/tmp/zulip-export-")
        if os.path.exists(output_dir):
            shutil.rmtree(output_dir)
        os.makedirs(output_dir)
        print("Exporting user %s" % (user_profile.email, ))
        do_export_user(user_profile, output_dir)
        print("Finished exporting to %s; tarring" % (output_dir, ))
        tarball_path = output_dir.rstrip('/') + '.tar.gz'
        subprocess.check_call(
            ["tar", "--strip-components=1", "-czf", tarball_path, output_dir])
        print("Tarball written to %s" % (tarball_path, ))