Просмотр исходного кода

WIP #406: UIServer implemented, needs tests

Rafał Pitoń 10 лет назад
Родитель
Сommit
eeb9eb5ef5

+ 1 - 1
misago/conf/defaults.py

@@ -62,7 +62,7 @@ PIPELINE_JS = {
             'misago/js/misago-yesnoswitch.js',
             'misago/js/misago-alerts.js',
             'misago/js/misago-ajax.js',
-            'misago/js/misago-events.js',
+            'misago/js/misago-uiserver.js',
             'misago/js/misago-notifications.js',
         ),
         'output_filename': 'misago.js',

+ 56 - 0
misago/core/uiviews.py

@@ -0,0 +1,56 @@
+"""
+Misago UI views controller
+
+UI views are small views that are called asynchronically to give UI knowledge
+of changes in APP state and thus opportunity to update themselves in real time
+"""
+from django.core.exceptions import PermissionDenied
+from django.core.urlresolvers import resolve
+from django.http import Http404, JsonResponse
+
+from misago.core.decorators import ajax_only
+from misago.core.utils import is_request_local
+
+
+__all__ = ['uiview', 'uiserver']
+
+
+UI_VIEWS = []
+
+
+def uiview(name):
+    """
+    Decorator for registering UI views
+    """
+    def namespace_decorator(f):
+        UI_VIEWS.append((name, f))
+        return f
+    return namespace_decorator
+
+
+def get_resolver_match(request):
+    if not is_request_local(request):
+        raise PermissionDenied()
+
+    requesting_path = request.META['HTTP_REFERER']
+    requesting_path = requesting_path[len(request.scheme) + 3:]
+    requesting_path = requesting_path[len(request.META['HTTP_HOST']):]
+
+    return resolve(requesting_path)
+
+
+@ajax_only
+def uiserver(request):
+    resolver_match = get_resolver_match(request)
+    response_dict = {'total_count': 0}
+
+    for name, view in UI_VIEWS:
+        try:
+            view_response = view(request, resolver_match)
+            if view_response:
+                response_dict['total_count'] += view_response.get('count', 0)
+                response_dict[name] = view_response
+        except (Http404, PermissionDenied):
+            pass
+
+    return JsonResponse(response_dict)

+ 17 - 0
misago/core/utils.py

@@ -79,6 +79,23 @@ def is_request_to_misago(request):
         return request._request_to_misago
 
 
+def is_request_local(request):
+    referer = request.META.get('HTTP_REFERER')
+
+    if not referer:
+        return False
+    if not referer.startswith(request.scheme):
+        return False
+    referer = referer[len(request.scheme) + 3:]
+    if not referer.startswith(request.META['HTTP_HOST']):
+        return False
+    referer = referer[len(request.META['HTTP_HOST'].rstrip('/')):]
+    if not referer.startswith('/'):
+        return False
+
+    return True
+
+
 """
 Utility that humanizes time amount.
 

+ 0 - 1
misago/notifications/urls.py

@@ -3,6 +3,5 @@ from django.conf.urls import include, patterns, url
 
 urlpatterns = patterns('misago.notifications.views',
     url(r'^notifications/$', 'notifications', name='notifications'),
-    url(r'^notifications/event-sender/$', 'event_sender', name='notifications_event_sender'),
     url(r'^notifications/new/$', 'new_notification', name='new_notification'),
 )

+ 5 - 8
misago/notifications/views.py

@@ -1,8 +1,7 @@
-from django.http import JsonResponse
 from django.shortcuts import render
 from django.utils.translation import ugettext as _, ungettext
 
-from misago.core.decorators import ajax_only
+from misago.core.uiviews import uiview
 
 from misago.users.decorators import deny_guests
 
@@ -32,9 +31,8 @@ def full_page(request):
     return render(request, 'misago/notifications/full.html')
 
 
-@ajax_only
-@deny_guests
-def event_sender(request):
+@uiview('misago_notifications')
+def event_sender(request, resolver_match):
     if request.user.new_notifications:
         message = ungettext("You have %(notifications)s new notification",
                             "You have %(notifications)s new notifications",
@@ -43,11 +41,10 @@ def event_sender(request):
     else:
         message = _("Your notifications")
 
-    return JsonResponse({
-        'is_error': False,
+    return {
         'count': request.user.new_notifications,
         'message': message,
-    })
+    }
 
 
 @deny_guests

+ 0 - 68
misago/static/misago/js/misago-events.js

@@ -1,68 +0,0 @@
-// Misago events extension
-(function($) {
-
-  // Events handler class definition
-  // ===============================
-
-  var MisagoEvents = function(frequency) {
-
-    if (frequency == undefined) {
-      this.frequency = 15000;
-    } else {
-      this.frequency = frequency;
-    }
-
-    this.listeners = [];
-    this.listener = function(url, callback) {
-      this.listeners.push({url: url, callback: callback});
-      this.poll(true);
-    };
-
-    this.poll = function(mute_timeout) {
-      var poll = this.poll;
-      var frequency = this.frequency;
-
-      var ajax_calls = [];
-      $.each(this.listeners, function(i, obj) {
-        ajax_calls.push($.get(obj.url));
-      });
-
-      var listeners = this.listeners;
-      $.when.apply($, ajax_calls).then(function () {
-          var _args = arguments;
-          var events_count = 0;
-
-          if (listeners.length == 1) {
-            var data = _args[0];
-            events_count = data.count;
-            listeners[0].callback(data);
-          } else {
-            $.each(listeners, function(i, obj) {
-              var data = _args[i][0];
-              events_count += data.count;
-              obj.callback(data);
-            });
-          }
-          Tinycon.setBubble(events_count);
-          if (mute_timeout === undefined || mute_timeout == false){
-            window.setTimeout(poll, frequency);
-          }
-      });
-    };
-    window.setTimeout(this.poll, this.frequency);
-
-    // Return object
-    return this;
-  };
-
-  // Plugin definition
-  // ==========================
-
-  $.misago_events = function(frequency) {
-    if ($._misago_events == undefined) {
-      $._misago_events = MisagoEvents(frequency);
-    }
-    return $._misago_events;
-  };
-
-}(jQuery));

+ 2 - 2
misago/static/misago/js/misago-notifications.js

@@ -27,8 +27,8 @@ $(function() {
     }
   }
 
-  if (typeof notifications_url !== "undefined") {
-    $.misago_events().listener(notifications_url, notifications_handler);
+  if (is_authenticated) {
+    $.misago_ui().observer("misago_notifications", notifications_handler);
   }
 
   var $display = $container.find('.display');

+ 58 - 0
misago/static/misago/js/misago-uiserver.js

@@ -0,0 +1,58 @@
+// Misago UI server
+(function($) {
+
+  // Class definition
+  // ===============================
+
+  var MisagoUIServer = function(frequency) {
+
+    if (frequency == undefined) {
+      frequency = 15000;
+    }
+
+    this.ui_observers = [];
+    this.observer = function(name, callback) {
+      this.ui_observers.push({name: name, callback: callback});
+      this.query_server();
+    };
+
+    this.query_server = function(poll) {
+      if (poll === undefined) {
+        poll = 0;
+      }
+
+      ui_observers = this.ui_observers
+      $.get(uiserver_url, function(data) {
+        $.each(ui_observers, function(i, observer) {
+          if (typeof data[observer.name] !== "undefined") {
+            observer.callback(data[observer.name]);
+          }
+        });
+
+        if (poll > 0) {
+          window.setTimeout(function() {
+            query_server(frequency);
+          }, poll);
+        }
+      });
+    };
+
+    window.setTimeout(function() {
+      query_server(frequency);
+    }, frequency);
+
+    // Return object
+    return this;
+  };
+
+  // Plugin definition
+  // ==========================
+
+  $.misago_ui = function(frequency) {
+    if ($._misago_ui == undefined) {
+      $._misago_ui = MisagoUIServer(frequency);
+    }
+    return $._misago_ui;
+  };
+
+}(jQuery));

+ 4 - 4
misago/templates/misago/base.html

@@ -31,6 +31,8 @@
 
     {# We include JavaScript at the end of page body so it renders faster #}
     <script lang="JavaScript">
+      var is_authenticated = {{ user.is_authenticated|yesno:"true,false" }};
+
       var lang_yes = "{% trans "Yes" %}";
       var lang_no = "{% trans "No" %}";
       var ajax_errors = {
@@ -38,9 +40,8 @@
         not_found: "{% trans "API link is invalid." %}",
         timeout: "{% trans "Request has timed out." %}"
       };
-      {% if user.is_authenticated %}
-      var notifications_url = "{% url 'misago:notifications_event_sender' %}";
-      {% endif %}
+
+      var uiserver_url = "{% url 'misago:uiserver' %}";
     </script>
     {% compressed_js 'misago' %}
     <script lang="JavaScript">
@@ -51,7 +52,6 @@
           info_template: "<div class=\"alert-div\"><p class=\"alert alert-info\"><span class=\"alert-icon fa fa-info-circle\"></span>%message% <button type=\"button\" class=\"close\">{% trans "Ok!" %}</button></p></div>",
           success_template: "<div class=\"alert-div\"><p class=\"alert alert-success\"><span class=\"alert-icon fa fa-check-circle\"></span>%message% <button type=\"button\" class=\"close\">{% trans "Ok!" %}</button></p></div>"
         });
-        $.misago_events();
       });
     </script>
     {% block javascripts %}{% endblock javascripts %}

+ 2 - 0
misago/urls.py

@@ -15,6 +15,8 @@ urlpatterns += patterns('',
     url(r'^', include('misago.legal.urls')),
     url(r'^', include('misago.users.urls')),
     url(r'^', include('misago.notifications.urls')),
+    # UI Server view that handles realtime updates of Misago UI
+    url(r'^ui-server/$', 'misago.core.uiviews.uiserver', name="uiserver"),
 )