diff --git a/dddp/__init__.py b/dddp/__init__.py index 0047026..3a16a98 100644 --- a/dddp/__init__.py +++ b/dddp/__init__.py @@ -1,6 +1,7 @@ """Django/PostgreSQL implementation of the Meteor DDP service.""" from __future__ import unicode_literals import os.path +import sys from pkg_resources import get_distribution, DistributionNotFound from gevent.local import local from dddp import alea @@ -89,9 +90,16 @@ class RandomStreams(object): return self._streams[key] +def serializer_factory(): + """Make a new DDP serializer.""" + from django.core.serializers import get_serializer + return get_serializer('ddp')() + + THREAD_LOCAL = ThreadLocal( alea_random=alea.Alea, random_streams=RandomStreams, + serializer=serializer_factory, ) METEOR_ID_CHARS = u'23456789ABCDEFGHJKLMNPQRSTWXYZabcdefghijkmnopqrstuvwxyz' diff --git a/dddp/api.py b/dddp/api.py index 05a1447..a2bee16 100644 --- a/dddp/api.py +++ b/dddp/api.py @@ -191,6 +191,8 @@ class Collection(APIMixin): qs = self.get_queryset(qs) user_rels = self.user_rel if user_rels: + if user is None: + return qs.none() # no user but we need one: return no objects. if isinstance(user_rels, basestring): user_rels = [user_rels] user_filter = None @@ -399,9 +401,9 @@ class DDP(APIMixin): this.error('Invalid publication name: %r' % name) return obj, created = Subscription.objects.get_or_create( - connection=this.ws.connection, + connection_id=this.ws.connection.pk, sub_id=id_, - user=this.request.user, + user_id=this.request.user.pk, defaults={ 'publication': pub.name, 'publication_class': '%s.%s' % ( diff --git a/dddp/migrations/0005_auto_20150427_1209.py b/dddp/migrations/0005_auto_20150427_1209.py new file mode 100644 index 0000000..c7adc86 --- /dev/null +++ b/dddp/migrations/0005_auto_20150427_1209.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +from django.conf import settings + + +class Migration(migrations.Migration): + + dependencies = [ + ('dddp', '0004_connection_server_addr'), + ] + + operations = [ + migrations.AlterField( + model_name='subscription', + name='user', + field=models.ForeignKey(blank=True, to=settings.AUTH_USER_MODEL, null=True), + preserve_default=True, + ), + ] diff --git a/dddp/models.py b/dddp/models.py index 2dc1cf9..8559ad7 100644 --- a/dddp/models.py +++ b/dddp/models.py @@ -136,7 +136,7 @@ class Subscription(models.Model, object): _publication_cache = {} connection = models.ForeignKey(Connection) sub_id = models.CharField(max_length=17) - user = models.ForeignKey(settings.AUTH_USER_MODEL) + user = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True) publication = models.CharField(max_length=255) publication_class = models.CharField(max_length=255) params_ejson = models.TextField(default='{}') diff --git a/dddp/msg.py b/dddp/msg.py index 9e0a3e4..5cf55de 100644 --- a/dddp/msg.py +++ b/dddp/msg.py @@ -1,17 +1,28 @@ """Django DDP utils for DDP messaging.""" +from copy import deepcopy from dddp import THREAD_LOCAL as this -from django.core.serializers import get_serializer - - -def serializer_factory(): - """Make a new DDP serializer.""" - return get_serializer('ddp')() +from django.db.models.expressions import ExpressionNode def obj_change_as_msg(obj, msg): """Generate a DDP msg for obj with specified msg type.""" - serializer = this.get('serializer', serializer_factory) + # check for F expressions + exps = [ + name for name, val in vars(obj).items() + if isinstance(val, ExpressionNode) + ] + if exps: + # clone and update obj with values but only for the expression fields + obj = deepcopy(obj) + # Django 1.8 makes obj._meta public --> pylint: disable=W0212 + for name, val in obj._meta.model.objects.values(*exps).get(pk=obj.pk): + setattr(obj, name, val) + + # run serialization now that all fields are "concrete" (not F expressions) + serializer = this.serializer data = serializer.serialize([obj])[0] + + # collection name is . name = data['model'] # cast ID as string diff --git a/dddp/websocket.py b/dddp/websocket.py index 0afe891..2f25385 100644 --- a/dddp/websocket.py +++ b/dddp/websocket.py @@ -123,7 +123,7 @@ class DDPWebSocketApplication(geventwebsocket.WebSocketApplication): this.send_msg = self.send_msg this.reply = self.reply this.error = self.error - this.session_key = this.request.session.session_key + this.request.session.save() this.remote_addr = self.remote_addr = \ '{0[REMOTE_ADDR]}:{0[REMOTE_PORT]}'.format( @@ -280,7 +280,7 @@ class DDPWebSocketApplication(geventwebsocket.WebSocketApplication): this.version = version this.support = support self.connection = Connection.objects.create( - session_id=this.session_key, + session_id=this.request.session.session_key, server_addr='%d:%s' % ( backend_pid, self.ws.handler.socket.getsockname(),