danyi1212 / drf-messages

Use Django's Messages Framework with Django Rest Framework project
https://drf-messages.readthedocs.io/en/latest
BSD 3-Clause "New" or "Revised" License
5 stars 4 forks source link

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

Open SaadBazaz opened 2 years ago

SaadBazaz commented 2 years ago

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.

danyi1212 commented 2 years ago

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

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:

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:

Tests for implementation

Where to implement

Three possible locations to add this feature:

Please provide you thoughts on my design