Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple Users in one Message (Bulk/Broadcast Message) #21

Open
SaadBazaz opened this issue Jan 2, 2022 · 1 comment
Open

Multiple Users in one Message (Bulk/Broadcast Message) #21

SaadBazaz opened this issue Jan 2, 2022 · 1 comment
Assignees
Labels
enhancement New feature or request

Comments

@SaadBazaz
Copy link
Contributor

Problem
To send a single message, e.g. an update alert message to users, or even a greeting for the holiday, I have to add a message for each user separately. This could clog up the database, specially since all the messages are the same, just the user is different.

Possible solution
A separate table with User -> Message mapping, an admin form/action for Bulk messages, etc.

Describe alternatives you've considered
Alternatives can be Firebase Messaging, but I would prefer a DRF-only solution.

@SaadBazaz SaadBazaz added the enhancement New feature or request label Jan 2, 2022
@danyi1212
Copy link
Owner

danyi1212 commented Jan 18, 2022

Interesting idea there, though I think this should be as an add-in to this package.

About the problem

I must point that usually messages from this package should not be persistent, and get deleted as soon as they are not relevant. This design is replicating the Django Messages framework, where the messages are stored in the session, and get deleted on logout.

With this in mind, it reduces the weight of creating many messages in the DB, because they will eventually get cleared when they will be read.

Stuff to think about

  • We must store for each user separately whether they have read the message or not
  • We must include them through the same API from DBStorage and MessagesViewSet
  • We must design it in a way that bulk messages could be cleared eventually, preferably in the same logic as regular messages

Design Idea

As you've said, create a new model that will store relation between a message and multiple users, each with info whether they've read the message or not.

Create a new storage object that will include those messages in the filtering, providing a similar interface like they are regular messages. This new storage should implement a way to send bulk messages to a list of users.

The user submitting the broadcast message, will create a new "master message" with relation for him.
Any other recipient of that message will have a row in the bulk message model. The "master message" should not get deleted until all related bulk messages are read.

Create a new API view set to create and check status of bulk messages.

How I would implement such thing

A new model that will obtain the relation between the user and the message:

class BulkMessage(models.Model):
    message = models.ForeignKey(Message, on_delete=models.CASCADE)
    user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)

    read_at = models.DateTimeField(blank=True, null=True, default=None, help_text="When the message was read.")

    class Meta:
        constraints = [
            models.UniqueConstraint(fields=("message", "user"), name="unique_bulk_message"),
        ]

It will contain a manager like on the classic Message that will have a filter for messages for a user and mark as read.

Some improvements for the DBStorage to replace any place the do mark_read with a storage method that will mark any unread messages as read (aka. self.get_unread_queryset().mark_read()). This will later be overriden.

Implement a new BulkDBStorage object that will inherit DBStorage and override functions:

  • get_queryset -> To include message relevant to the request by the relation with the user through BulkMessage
  • get_unread_queryset - > To include unread message from the relation through BulkMessage
  • mark_all_read -> Mark read any messages that are directly attached to the request.user, and also any BulkMessage for that user.

There a new method can be implemented like:

def add_bulk(self, recipients: Sequence[User], level: int, message: str, extra_tags=''):
    message = Message.objects.create_message(self.request, message, level, extra_tags=extra_tags)
    BulkMessage.objects.bulk_create([
        BulkMessage(message=message, user=user)
        for user in recipients
    ])

Implement a viewset, with the methods:

  • create -> Send a new bulk message
  • list -> List all bulk messages with count aggregation for recipients and read messages
  • get -> Get specific bulk message with the list of recipients (users)

Tests for implementation

  • Create a new bulk message
    • As the sender, should see bulk message on my "unread messages"
    • As a recipient, should see it on my "unread messages"
    • After sender reads the master message, it is not deleted
    • After recipient reads a bulk message, the master message is not marked as read
    • After recipient reads a bulk message, the bulk message is marked as read
    • All recipients have read the message, it can be / have been deleted

Where to implement

Three possible locations to add this feature:

  • As a "contrib" app, separately from the main package app (such as drf_message.bulk_messages)
  • As a separate PyPI package inside this repo, with dependency drf-messages (such as drf-messages-bulk)
  • As a separate repo as stand-alone PyPI package with dependency for drf-messages

Please provide you thoughts on my design

@danyi1212 danyi1212 self-assigned this Jan 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants