コード例 #1
0
def do_soft_deactivate_user(user_profile: UserProfile) -> None:
    try:
        user_profile.last_active_message_id = (UserMessage.objects.filter(
            user_profile=user_profile).order_by("-message_id")[0].message_id)
    except IndexError:  # nocoverage
        # In the unlikely event that a user somehow has never received
        # a message, we just use the overall max message ID.
        user_profile.last_active_message_id = Message.objects.last().id
    user_profile.long_term_idle = True
    user_profile.save(
        update_fields=["long_term_idle", "last_active_message_id"])
    logger.info("Soft deactivated user %s", user_profile.id)
コード例 #2
0
def do_soft_deactivate_user(user_profile: UserProfile) -> None:
    try:
        user_profile.last_active_message_id = UserMessage.objects.filter(
            user_profile=user_profile).order_by('-message__id')[0].message_id
    except IndexError:  # nocoverage
        # In the unlikely event that a user somehow has never received
        # a message, we just use the overall max message ID.
        user_profile.last_active_message_id = Message.objects.max().id
    user_profile.long_term_idle = True
    user_profile.save(
        update_fields=['long_term_idle', 'last_active_message_id'])
    logger.info('Soft Deactivated user %s' % (user_profile.id, ))
コード例 #3
0
ファイル: soft_deactivation.py プロジェクト: deltay/zulip
def do_soft_deactivate_user(user_profile: UserProfile) -> None:
    try:
        user_profile.last_active_message_id = UserMessage.objects.filter(
            user_profile=user_profile).order_by(
                '-message__id')[0].message_id
    except IndexError:  # nocoverage
        # In the unlikely event that a user somehow has never received
        # a message, we just use the overall max message ID.
        user_profile.last_active_message_id = Message.objects.max().id
    user_profile.long_term_idle = True
    user_profile.save(update_fields=[
        'long_term_idle',
        'last_active_message_id'])
    logger.info('Soft Deactivated user %s (%s)' %
                (user_profile.id, user_profile.email))
コード例 #4
0
def do_soft_deactivate_user(user_profile: UserProfile) -> None:
    user_profile.last_active_message_id = UserMessage.objects.filter(
        user_profile=user_profile).order_by('-message__id')[0].message_id
    user_profile.long_term_idle = True
    user_profile.save(
        update_fields=['long_term_idle', 'last_active_message_id'])
    logger.info('Soft Deactivated user %s (%s)' %
                (user_profile.id, user_profile.email))
コード例 #5
0
ファイル: soft_deactivation.py プロジェクト: 284928489/zulip
def do_soft_deactivate_user(user_profile: UserProfile) -> None:
    user_profile.last_active_message_id = UserMessage.objects.filter(
        user_profile=user_profile).order_by(
        '-message__id')[0].message_id
    user_profile.long_term_idle = True
    user_profile.save(update_fields=[
        'long_term_idle',
        'last_active_message_id'])
    logger.info('Soft Deactivated user %s (%s)' %
                (user_profile.id, user_profile.email))
コード例 #6
0
def add_missing_messages(user_profile: UserProfile) -> None:
    """This function takes a soft-deactivated user, and computes and adds
    to the database any UserMessage rows that were not created while
    the user was soft-deactivated.  The end result is that from the
    perspective of the message database, it should be impossible to
    tell that the user was soft-deactivated at all.

    At a high level, the algorithm is as follows:

    * Find all the streams that the user was at any time a subscriber
      of when or after they were soft-deactivated (`recipient_ids`
      below).

    * Find all the messages sent to those streams since the user was
      soft-deactivated.  This will be a superset of the target
      UserMessages we need to create in two ways: (1) some UserMessage
      rows will have already been created in do_send_messages because
      the user had a nonzero set of flags (the fact that we do so in
      do_send_messages simplifies things considerably, since it means
      we don't need to inspect message content to look for things like
      mentions here), and (2) the user might not have been subscribed
      to all of the streams in recipient_ids for the entire time
      window.

    * Correct the list from the previous state by excluding those with
      existing UserMessage rows.

    * Correct the list from the previous state by excluding those
      where the user wasn't subscribed at the time, using the
      RealmAuditLog data to determine exactly when the user was
      subscribed/unsubscribed.

    * Create the UserMessage rows.

    For further documentation, see:

      https://zulip.readthedocs.io/en/latest/subsystems/sending-messages.html#soft-deactivation

    """
    assert user_profile.last_active_message_id is not None
    all_stream_subs = list(
        Subscription.objects.filter(user_profile=user_profile,
                                    recipient__type=Recipient.STREAM).values(
                                        "recipient_id", "recipient__type_id"))

    # For Stream messages we need to check messages against data from
    # RealmAuditLog for visibility to user. So we fetch the subscription logs.
    stream_ids = [sub["recipient__type_id"] for sub in all_stream_subs]
    events = [
        RealmAuditLog.SUBSCRIPTION_CREATED,
        RealmAuditLog.SUBSCRIPTION_DEACTIVATED,
        RealmAuditLog.SUBSCRIPTION_ACTIVATED,
    ]

    # Important: We order first by event_last_message_id, which is the
    # official ordering, and then tiebreak by RealmAuditLog event ID.
    # That second tiebreak is important in case a user is subscribed
    # and then unsubscribed without any messages being sent in the
    # meantime.  Without that tiebreak, we could end up incorrectly
    # processing the ordering of those two subscription changes.
    subscription_logs = list(
        RealmAuditLog.objects.select_related("modified_stream").filter(
            modified_user=user_profile,
            modified_stream_id__in=stream_ids,
            event_type__in=events).order_by("event_last_message_id", "id"))

    all_stream_subscription_logs: DefaultDict[
        int, List[RealmAuditLog]] = defaultdict(list)
    for log in subscription_logs:
        all_stream_subscription_logs[log.modified_stream_id].append(log)

    recipient_ids = []
    for sub in all_stream_subs:
        stream_subscription_logs = all_stream_subscription_logs[
            sub["recipient__type_id"]]
        if stream_subscription_logs[
                -1].event_type == RealmAuditLog.SUBSCRIPTION_DEACTIVATED:
            assert stream_subscription_logs[
                -1].event_last_message_id is not None
            if (stream_subscription_logs[-1].event_last_message_id <=
                    user_profile.last_active_message_id):
                # We are going to short circuit this iteration as its no use
                # iterating since user unsubscribed before soft-deactivation
                continue
        recipient_ids.append(sub["recipient_id"])

    all_stream_msgs = list(
        Message.objects.filter(
            recipient_id__in=recipient_ids,
            id__gt=user_profile.last_active_message_id).order_by("id").values(
                "id", "recipient__type_id"))
    already_created_ums = set(
        UserMessage.objects.filter(
            user_profile=user_profile,
            message__recipient__type=Recipient.STREAM,
            message_id__gt=user_profile.last_active_message_id,
        ).values_list("message_id", flat=True))

    # Filter those messages for which UserMessage rows have been already created
    all_stream_msgs = [
        msg for msg in all_stream_msgs if msg["id"] not in already_created_ums
    ]

    stream_messages: DefaultDict[int, List[Message]] = defaultdict(list)
    for msg in all_stream_msgs:
        stream_messages[msg["recipient__type_id"]].append(msg)

    # Calling this function to filter out stream messages based upon
    # subscription logs and then store all UserMessage objects for bulk insert
    # This function does not perform any SQL related task and gets all the data
    # required for its operation in its params.
    user_messages_to_insert = filter_by_subscription_history(
        user_profile, stream_messages, all_stream_subscription_logs)

    # Doing a bulk create for all the UserMessage objects stored for creation.
    while len(user_messages_to_insert) > 0:
        messages, user_messages_to_insert = (
            user_messages_to_insert[0:BULK_CREATE_BATCH_SIZE],
            user_messages_to_insert[BULK_CREATE_BATCH_SIZE:],
        )
        UserMessage.objects.bulk_create(messages)
        user_profile.last_active_message_id = messages[-1].message_id
        user_profile.save(update_fields=["last_active_message_id"])