Skip to content

Commit

Permalink
Realtime notifications for pages with the same link
Browse files Browse the repository at this point in the history
For any filter-type websocket message the clauses are scanned.
For all uri clauses the equivalent uris are fetched (with the
document plugin) and placed into the filter payload.

This way an annotation created in one of the linked pages is
sent via websocket to every linked pages

Fix #1815
  • Loading branch information
gergely-ujvari committed Mar 23, 2015
1 parent 393f082 commit cc7584e
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 6 deletions.
26 changes: 26 additions & 0 deletions h/streamer.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from ws4py.server.wsgiutils import WebSocketWSGIApplication

from .api.auth import get_user # FIXME: should not import from .api
from annotator import document
from .models import Annotation

log = logging.getLogger(__name__)
Expand Down Expand Up @@ -473,6 +474,27 @@ def send_annotations(self):
data = json.dumps(packet)
self.send(data)

def _expand_clauses(self, payload):
for clause in payload['clauses']:
if clause['field'] == '/uri':
self._expand_uris(clause)

def _expand_uris(self, clause):
uris = clause['value']
if not isinstance(uris, list):
uris = [uris]

if len(uris) < 1:
return

available_uris = set(uris)
for uri in uris:
doc = document.Document.get_by_uri(uri)
for eq_uri in doc.uris():
available_uris.add(eq_uri)

clause['value'] = list(available_uris)

def received_message(self, msg):
transaction.begin()
try:
Expand All @@ -485,6 +507,10 @@ def received_message(self, msg):

# Let's try to validate the schema
validate(payload, filter_schema)

# Add backend expands for clauses
self._expand_clauses(payload)

self.filter = FilterHandler(payload)
self.query = FilterToElasticFilter(payload, self.request)
self.offsetFrom = 0
Expand Down
44 changes: 38 additions & 6 deletions h/test/streamer_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import json

from mock import ANY
from mock import MagicMock
from mock import MagicMock, Mock
from mock import patch
from pyramid.testing import DummyRequest

Expand Down Expand Up @@ -214,15 +214,47 @@ def test_websocket_same_origin(config):


class TestWebSocket(unittest.TestCase):
def test_opened_starts_reader(self):
def setUp(self):
fake_request = MagicMock()
fake_socket = MagicMock()

s = WebSocket(fake_socket)
s.request = fake_request
s.opened()
self.s = WebSocket(fake_socket)
self.s.request = fake_request

s.request.get_queue_reader.assert_called_once_with('annotations', ANY)
def test_opened_starts_reader(self):
self.s.opened()
self.s.request.get_queue_reader.assert_called_once_with('annotations', ANY)

def test_filter_message_with_uri_gets_patched(self):
filter_message = json.dumps({
'filter': {
'actions': {},
'match_policy': 'include_all',
'clauses': [{
'field': '/uri',
'operator': 'equals',
'value': 'http://example.com',
}],
}
})

with patch('annotator.document.Document.get_by_uri') as doc:
uris = Mock()
uris.return_value = ['http://example.com',
'http://example.com/alter',
'http://example.com/print']
doc.return_value = Mock(uris=uris)
msg = MagicMock()
msg.data = filter_message

self.s.received_message(msg)

uri_filter = self.s.filter.filter['clauses'][0]
uri_values = uri_filter['value']
assert len(uri_values) == 3
assert 'http://example.com' in uri_values
assert 'http://example.com/alter' in uri_values
assert 'http://example.com/print' in uri_values


class TestBroadcast(unittest.TestCase):
Expand Down

0 comments on commit cc7584e

Please sign in to comment.