Skip to content

Commit

Permalink
Initial implementation of the sync API endpoint. Fix #182
Browse files Browse the repository at this point in the history
  • Loading branch information
aarranz committed May 30, 2016
1 parent 9ffdd48 commit d892294
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 0 deletions.
Empty file added src/wirecloud/live/__init__.py
Empty file.
40 changes: 40 additions & 0 deletions src/wirecloud/live/consumers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-

# Copyright (c) 2016 CoNWeT Lab., Universidad Politécnica de Madrid

# This file is part of Wirecloud.

# Wirecloud is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# Wirecloud is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.

# You should have received a copy of the GNU Affero General Public License
# along with Wirecloud. If not, see <http://www.gnu.org/licenses/>.

from channels import Group
from channels.auth import channel_session_user, channel_session_user_from_http


@channel_session_user_from_http
def ws_connect(message):
Group("wc-live-%s" % message.user.username).add(message.reply_channel)
Group("wc-live-*").add(message.reply_channel)


@channel_session_user
def ws_message(message):
Group("chat-%s" % message.channel_session['room']).send({
"text": message['text'],
})


@channel_session_user
def ws_disconnect(message):
Group("wc-live-%s" % message.user.username).discard(message.reply_channel)
Group("wc-live-*").discard(message.reply_channel)
91 changes: 91 additions & 0 deletions src/wirecloud/live/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# -*- coding: utf-8 -*-

# Copyright (c) 2016 CoNWeT Lab., Universidad Politécnica de Madrid

# This file is part of Wirecloud.

# Wirecloud is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# Wirecloud is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.

# You should have received a copy of the GNU Affero General Public License
# along with Wirecloud. If not, see <http://www.gnu.org/licenses/>.

from __future__ import unicode_literals

import json

from channels import Group
from django.dispatch import receiver
from django.db.models.signals import m2m_changed, post_save
import requests

from wirecloud.platform.models import CatalogueResource, Workspace


def notify(data, affected_users):
for user in affected_users:
Group('wc-live-%s' % user).send({"text": json.dumps(data)})


def get_affected_users(instance):

if instance.public:
return '*'
else:
affected_users = set(instance.users.values_list("username", flat=True))
for group in instance.groups.all():
affected_users.update(group.user_set.values_list("username", flat=True))
return ",".join(affected_users)


@receiver(post_save, sender=Workspace)
def workspace_update(sender, instance, created, raw, **kwargs):

affected_users = get_affected_users(instance)

if affected_users != '':
notify(
{
"workspace": instance.id,
"action": "update",
},
affected_users
)


@receiver(m2m_changed, sender=CatalogueResource.groups.through)
@receiver(m2m_changed, sender=CatalogueResource.users.through)
def update_users_or_groups(sender, instance, action, reverse, model, pk_set, using, **kwargs):
if reverse or action.startswith('pre_') or (pk_set is not None and len(pk_set) == 0):
return

affected_users = ",".join(model.objects.filter(pk__in=pk_set).values_list("username", flat=True))
notify(
{
"component": instance.local_uri_part,
"action": "installed" if action == "post_add" else "uninstalled"
},
affected_users
)


@receiver(post_save, sender=CatalogueResource)
def mac_update(sender, instance, created, raw, **kwargs):

affected_users = get_affected_users(instance)

if affected_users != '':
notify(
{
"component": instance.local_uri_part,
"action": "update",
},
affected_users
)
27 changes: 27 additions & 0 deletions src/wirecloud/live/routing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-

# Copyright (c) 2016 CoNWeT Lab., Universidad Politécnica de Madrid

# This file is part of Wirecloud.

# Wirecloud is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# Wirecloud is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.

# You should have received a copy of the GNU Affero General Public License
# along with Wirecloud. If not, see <http://www.gnu.org/licenses/>.

from channels.routing import route
from wirecloud.live.consumers import ws_connect, ws_message, ws_disconnect

channel_routing = [
route("websocket.connect", ws_connect, path="^/api/live"),
route("websocket.receive", ws_message),
route("websocket.disconnect", ws_disconnect),
]
60 changes: 60 additions & 0 deletions src/wirecloud/live/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-

# Copyright (c) 2016 CoNWeT Lab., Universidad Politécnica de Madrid

# This file is part of Wirecloud.

# Wirecloud is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# Wirecloud is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.

# You should have received a copy of the GNU Affero General Public License
# along with Wirecloud. If not, see <http://www.gnu.org/licenses/>.

from __future__ import unicode_literals

import datetime

from django.contrib.auth.models import User
from mock import patch

from wirecloud.commons.utils.testcases import WirecloudTestCase
from wirecloud.platform.models import CatalogueResource, Workspace

@patch('wirecloud.live.models.notify')
class LiveNotificationsTestCase(WirecloudTestCase):

fixtures = ('selenium_test_data',)
tags = ('wirecloud-noselenium', 'wirecloud-live')

def setUp(self):
self.normuser = User.objects.get(username="normuser")

def test_new_macs_are_notified(self, notify_mock):
instance = CatalogueResource.objects.create(type=1, creation_date=datetime.datetime.now(), short_name="MyWidget", vendor="Wirecloud", version="1.0")
instance.users.add(self.normuser)
notify_mock.assert_called_once_with(
{
"component": "Wirecloud/MyWidget/1.0",
"action": "installed"
},
"normuser"
)

def test_workspace_updates_are_notified(self, notify_mock):
instance = Workspace.objects.get(pk="2")
instance.description = "New description"
instance.save()
notify_mock.assert_called_once_with(
{
"workspace": 2,
"action": "update"
},
"user_with_workspaces"
)

0 comments on commit d892294

Please sign in to comment.