Skip to content

Commit

Permalink
rref #5367
Browse files Browse the repository at this point in the history
rref #5366
ref #66
ref #65
  • Loading branch information
evrenesat committed Jun 23, 2016
1 parent bfdfc10 commit 6ebcf44
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 11 deletions.
17 changes: 16 additions & 1 deletion zengine/lib/utils.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@

# -*- coding: utf-8 -*-

class DotDict(dict):
"""
A dict object that support dot notation for item access.
Slower that pure dict.
"""

def __getattr__(self, attr):
return self.get(attr, None)

Expand All @@ -17,10 +18,24 @@ def date_to_solr(d):
""" converts DD-MM-YYYY to YYYY-MM-DDT00:00:00Z"""
return "{y}-{m}-{day}T00:00:00Z".format(day=d[:2], m=d[3:5], y=d[6:]) if d else d


def solr_to_date(d):
""" converts YYYY-MM-DDT00:00:00Z to DD-MM-YYYY """
return "{day}:{m}:{y}".format(y=d[:4], m=d[5:7], day=d[8:10]) if d else d


def solr_to_year(d):
""" converts YYYY-MM-DDT00:00:00Z to DD-MM-YYYY """
return d[:4]

import re
def to_safe_str(s):
"""
converts some (tr) non-ascii chars to ascii counterparts,
then return the result as lowercase
"""
# TODO: This is insufficient as it doesn't do anything for other non-ascii chars
return re.sub(r'[^0-9a-zA-Z]+', '_', s.strip().replace(u'ğ', 'g').replace(u'ö', 'o').replace(
u'ç', 'c').replace(u'Ç','c').replace(u'Ö', u'O').replace(u'Ş', 's').replace(
u'Ü', 'u').replace(u'ı', 'i').replace(u'İ','i').replace(u'Ğ', 'g').replace(
u'ö', 'o').replace(u'ş', 's').replace(u'ü', 'u').lower(), re.UNICODE)
6 changes: 3 additions & 3 deletions zengine/management_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,18 +195,18 @@ class PrepareMQ(Command):

def run(self):
self.create_user_channels()
self.create_exchanges()
self.create_channel_exchanges()

def create_user_channels(self):
from zengine.messaging.model import Channel
user_model = get_object_from_path(settings.USER_MODEL)
for usr in user_model.objects.filter():
ch, new = Channel.objects.get_or_create(owner=usr, is_private=True)
print("%s exchange: %s" % ('created' if new else 'existing', ch.name))
print("%s exchange: %s" % ('created' if new else 'existing', ch.code_name))

def create_channel_exchanges(self):
from zengine.messaging.model import Channel
for ch in Channel.objects.filter():
print("(re)creation exchange: %s" % ch.name)
print("(re)creation exchange: %s" % ch.code_name)
ch.create_exchange()

4 changes: 2 additions & 2 deletions zengine/messaging/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ def send_message(self, title, message, sender=None, url=None, typ=1):
mq_msg['sender_key'] = sender.key

mq_channel.basic_publish(exchange=self.key, body=json.dumps(mq_msg))
self._write_message(sender, message, title, url, typ)
self._write_message_to_db(sender, message, title, url, typ)

def _write_message(self, sender, body, title, url, typ):
def _write_message_to_db(self, sender, body, title, url, typ):
from zengine.messaging.model import Channel, Message
channel = Channel.objects.get(owner=self, is_private=True)
Message(channel=channel, sender=sender, msg_title=title,
Expand Down
54 changes: 49 additions & 5 deletions zengine/messaging/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@

from pyoko import Model, field, ListNode
from pyoko.conf import settings
from pyoko.exceptions import IntegrityError
from pyoko.lib.utils import get_object_from_path
from zengine.client_queue import BLOCKING_MQ_PARAMS
from zengine.lib.utils import to_safe_str

UserModel = get_object_from_path(settings.USER_MODEL)

Expand All @@ -33,6 +35,15 @@ def get_mq_connection():


class Channel(Model):
"""
Represents MQ exchanges.
is_private: Represents users exchange hub
Each user have a durable private exchange,
which their code_name composed from user key prefixed with "prv_"
is_direct: Represents a user-to-user direct message exchange
"""
channel = None
connection = None

Expand All @@ -53,11 +64,37 @@ class Meta:
class Managers(ListNode):
user = UserModel(reverse_name='managed_channels')

def add_message(self, body, title, sender=None, url=None, typ=2):
@classmethod
def get_or_create_direct_channel(cls, initiator, receiver):
"""
Creates a direct messaging channel between two user
Args:
initiator: User, who sent the first message
receiver: User, other party
Returns:
Channel
"""
existing = cls.objects.or_filter(
code_name='%s_%s' % (initiator.key, receiver.key)).or_filter(
code_name='%s_%s' % (receiver.key, initiator.key))
if existing:
return existing[0]
else:
channel_name = '%s_%s' % (initiator.key, receiver.key)
channel = cls(is_direct=True, code_name=channel_name).save()
Subscription(channel=channel, user=initiator).save()
Subscription(channel=channel, user=receiver).save()
return channel


def add_message(self, body, title, sender=None, url=None, typ=2, receiver=None):
channel = self._connect_mq()
mq_msg = json.dumps(dict(sender=sender, body=body, msg_title=title, url=url, typ=typ))
channel.basic_publish(exchange=self.code_name, body=mq_msg)
Message(sender=sender, body=body, msg_title=title, url=url, typ=typ, channel=self).save()
Message(sender=sender, body=body, msg_title=title, url=url,
typ=typ, channel=self, receiver=receiver).save()

@classmethod
def _connect_mq(cls):
Expand All @@ -75,7 +112,13 @@ def create_exchange(self):

def pre_creation(self):
if not self.code_name:
self.code_name = self.key
if self.name:
self.code_name = to_safe_str(self.name)
return
if self.owner and self.is_private:
self.code_name = "prv_%s" % to_safe_str(self.owner.key)
return
raise IntegrityError('Non-private and non-direct channels should have a "name".')

def post_creation(self):
self.create_exchange()
Expand All @@ -89,7 +132,8 @@ class Subscription(Model):
channel = Channel()
user = UserModel(reverse_name='channels')
is_muted = field.Boolean("Mute the channel")
inform_me = field.Boolean("Inform when I'm mentioned")
inform_me = field.Boolean("Inform when I'm mentioned", default=True)
visible = field.Boolean("Show under user's channel list", default=True)
can_leave = field.Boolean("Membership is not obligatory", default=True)

# status = field.Integer("Status", choices=SUBSCRIPTION_STATUS)
Expand All @@ -108,7 +152,7 @@ def create_exchange(self):
we always call it before binding it to related channel
"""
channel = self._connect_mq()
channel.exchange_declare(exchange=self.user.key, exchange_type='direct', durable=True)
channel.exchange_declare(exchange=self.user.key, exchange_type='fanout', durable=True)

def bind_to_channel(self):
"""
Expand Down
48 changes: 48 additions & 0 deletions zengine/messaging/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
"""
"""

# Copyright (C) 2015 ZetaOps Inc.
#
# This file is licensed under the GNU General Public License v3
# (GPLv3). See LICENSE.txt for details.
from pyoko.conf import settings
from pyoko.lib.utils import get_object_from_path
from zengine.views.base import BaseView
UserModel = get_object_from_path(settings.USER_MODEL)

class MessageView(BaseView):

def create_message(self):
"""
Creates a message for the given channel.
Args:
self.current.input['data']['message'] = {
'channel': code_name of the channel
'title': Title of the message, optional
'body': Title of the message
'attachment':{
'name': title/name of file
'key': storage key
}
}
"""
# TODO: Attachment support!!!
msg = self.current.input['message']

# UserModel.objects.get(msg['receiver']).send_message(msg.get('title'), msg['body'], typ=2,
# sender=self.current.user)



def new_broadcast_message(self):
pass

def show_channel(self):
pass


def list_channels(self):
pass

0 comments on commit 6ebcf44

Please sign in to comment.