fanout / django-eventstream

Server-Sent Events for Django
MIT License
664 stars 88 forks source link

Read/unread events #54

Closed paolodina closed 4 years ago

paolodina commented 4 years ago

Hi, I'm trying to change how the event persistence works. The goal is is to keep track of unread events so that the user can retrieve unread messages. I'd appreciate any opinion on what I'm doing.

In my project each user has a dedicated channel identified by user pk. I was able to accomplish this with the following code:

urls.py:

urlpatterns = [
    ...
    path('events/<str:channel>)/', include(django_eventstream.urls)),
    ...

channelmanager.py subclass:

class ChannelManager(DefaultChannelManager):
    def can_read_channel(self, user, channel):
        return str(user.pk) == channel

To keep track of read/unread status I added a model and a post_save signal.

models.py

class EventTracker(models.Model):
    event = models.ForeignKey(Event, on_delete=models.CASCADE)
    read_date = models.DateTimeField(db_index=True, default=None, blank=True, null=True)
@receiver(post_save, sender=Event)
def eventstream_post_save(sender, instance, raw, using, update_fields, **kwargs):
    if (instance.type) == 'message':
        EventTracker.objects.create(event=instance, read_date=None)

And this is the context processor I use to pass unread messages counter to the template:

def messages(request):
    unread = EventTracker.objects.filter(
        event__channel=request.user.pk, event__type="message", read_date__isnull=True
    )

    return {'unread_messages_count': unread.count()}

It's a draft and I didn't test it well, but it seems to work. I have a couple of questions:

Questions:

If you consider these changes useful I and if you want, I could create a pull request.

Thanks

jkarneges commented 4 years ago

Is this for a Facebook-style notification inbox, where the user can view a list of items and choose which ones to read, and potentially read them out of order?

Personally, I'd consider application data such as messaging/notification inbox items to be separate from an event queue used for realtime delivery, and so I'd probably implement these things separately. In other words, build the inbox feature using its own database tables, and get all the user flows working (add, read, expire, etc) without any live updates. Then use django-eventstream only for the live updates.

This is just a personal preference though. Your way sounds like it would work fine, and it would use less data in the DB since you'd be sharing with django-eventstream's table. Your proposed changes to the lib seem small and reasonable if you want to create a PR.

BTW, another way to share tables could be to implement a custom storage class. Then instead of storing your long term app data in django-eventstream's tables, you could have django-eventstream read from your app's tables. I haven't really explored this yet though.

paolodina commented 4 years ago

Ok, the proposed changes weren't easy to implement for me (they had side effects I wasn't able to accomodate in a generic way for a PR), I forked the repo and did the changes I needed. Not ideal but it worked.

Thanks for you support, I think this ticket can be closed.

jkarneges commented 4 years ago

Thanks for following up. I'm glad you got something working.