pusher / django-pusherable

Real time notification when an object view is accessed via Pusher
BSD 3-Clause "New" or "Revised" License
55 stars 7 forks source link

Initial ideas on how to make this a little more robust #5

Open chrisjones-brack3t opened 9 years ago

chrisjones-brack3t commented 9 years ago

I'll allow it

Initial ideas on how to make this a little more robust

I haven't included any tests nor is this complete. This is more for presenting a different direction for the mixins. I've pulled some ideas and code from my own project django-braces.

I removed the render_to_response method from the mixin itself and moved that to the PusherDetailMixin.

PusherUpdateMixin overrides the form_valid method.

PusherDeleteMixin overrides the delete method.

This isn't complete by any means but it does work. If you like the direction I was headed with this, I can flesh it out some more and obviously add docs and tests.

aaronbassett commented 9 years ago

Hey @chrisjones-brack3t I love this approach, thanks for taking the time to put this PR together.

leggetter commented 9 years ago

I was thinking about pre and post update events. How about simply updating and updated?

aaronbassett commented 9 years ago

What if you want to subscribe to all events related to an update action? With namespacing you could just check if an event occurs within a particular namespace rather than check for each individual event name.

if(event.split(":")[0] === "update") { . . . }

vs

if(event === "updating" || event === "updated" || event === "update-failed") { . . . }
chrisjones-brack3t commented 9 years ago

@aaronbassett I agree about repeating the same lines. I had planned to handle that, just didn't get to it. Wanted to make sure my approach was worth putting more time into.

I think having multiple notifications triggered per view means the main PusherMixin needs some changes. Not entirely sure how to approach that yet. In prep for that, I went for a singleton approach with the main pusher connection on the mixin. Something like:

def _set_pusher(self):
    if hasattr(self, 'pusher') and isinstance(self.pusher, Pusher):
        return
    ...

My thought was having mixins for each type of event. So you'd have an UpdateSuccessMixin/UpdateFailedMixin which triggers a notification in the form_valid/form_invalid methods. You could also have an UpdateExpectedMixin which triggers a notification on the get method. I still wouldn't use render_to_response here because if the post has validation errors, I believe it will call render_to_response again. You could then inherit as many of these smaller mixins as you want and you have more options.

class SomeUpdateView(UpdateSuccessMixin, UpdateFailedMixin,
                     UpdateExpectedMixin, UpdateView):

If that feels like too much, you could also provide an UpdateAllTheThingsMixin which is basically a convenience mixin that combines all 3.

class UpdateAllTheThingsMixin(UpdateSuccessMixin, UpdateFailedMixin,
                              UpdateExpectedMixin):
    pass

On the subscription side of things, at least for the use cases I was thinking about, I think it makes sense to use Pusher's bind_all event. I think if you are looking at a detail view, update form view or delete view, it makes sense to receive notifications about any event that pertains to that object. For example, I'm editing a blog post and a user visits the detail view. It would be handy to know someone is looking at an object that I am about to change. Maybe I'm updating a blog post and another user is going to delete the post. Just a thought.

robslotboom commented 9 years ago

I think you're right to move the sending of the Pusher event from render_to_response on the Delete and Update views. But I still think there is a case for knowing when some has begun viewing the update form, not just when the form has saved successfully. Perhaps we could namespace the pusher_event_name. I'm not sure of the best way to achieve this, but we could send an event name of update:start in the get method and update:complete in the form_valid. Thoughts?

Hi Folks!

In an application I build, the user is only informed after some real change. I ended up using form.has_changed() for this.

Cheers,

Robert

aaronbassett commented 9 years ago

@chrisjones-brack3t :+1: on having mixins for each event type, I don't think we even need the UpdateAllTheThingsMixin, explicit is better than implicit, and all that.

As for subscribing to events on the client-side I agree with the bind_all. It might be an idea to allow users to specify a Javascript object as the callback which contains methods for each event type they want to handle. Sort of like the http_method_names and the dispatch method in CBVs. This would also close #3. I'll have a look at the client-side code after DjangoCon.

@robslotboom that's a great idea, no sense in notifying users of a form submission where no data has been changed.

chrisjones-brack3t commented 9 years ago

Okay, I took one more stab at this and refactored a lot.

I removed the leading underscores for all methods on PusherMixin except for _object_to_json_serializable. Every one of these methods could be overridden so it didn't seem to make sense to mark them as "private".

I'm not sure how widely used this package is yet. I realize my changes are not backwards compatible. Do you care about backwards incompatibility at this point?

leggetter commented 9 years ago

Sorry for the radio silence. I'm still catching up from DjangoCon EU!

So, to summarise from a simple usability point of view. It's possible to send an event through Pusher when somebody:

I'd maybe suggested viewing rather than viewed since the user may still be viewing after the event is triggered.

pending is a state that feels it should have a follow-on event and that's not always the case e.g. delete_pending may not be succeeded by a delete_succeeded. The user might just not do anything. However, I can't think of an alternative suggestion so I'd be happy to stick with what's in this PR.

The other main thing I'd really like to see is Pusher's evented pub/sub paradigm shine through (as per #3). However, I'll leave that for a separate discussion in that thread.

@aaronbassett @chrisjones-brack3t - it seems that @kennethlove has raised a few valid questions. Once those have been responded to and a solution agreed upon I'd like to try out the updated package on an app to see how it feels when using it.

decentral1se commented 8 years ago

Bump!

pusher-ci commented 4 years ago

@chrisjones-brack3t: PR needs rebase.

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md). If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
pusher-ci commented 4 years ago

@chrisjones-brack3t: PR needs rebase.

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md). If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
pusher-ci commented 4 years ago

@chrisjones-brack3t: PR needs rebase.

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md). If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.