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 28, 2016
1 parent 2afff44 commit 4040086
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 25 deletions.
21 changes: 21 additions & 0 deletions zengine/messaging/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,21 @@

from pyoko.conf import settings
from zengine.client_queue import BLOCKING_MQ_PARAMS
from zengine.lib.cache import Cache


class ConnectionStatus(Cache):
"""
Cache object for workflow instances.
Args:
wf_token: Token of the workflow instance.
"""
PREFIX = 'ONOFF'

def __init__(self, user_id):
super(ConnectionStatus, self).__init__(user_id)


class BaseUser(object):
connection = None
Expand Down Expand Up @@ -48,6 +61,14 @@ def set_password(self, raw_password):
self.password = pbkdf2_sha512.encrypt(raw_password, rounds=10000,
salt_size=10)

def is_online(self, status=None):
if status is None:
return ConnectionStatus(self.key).get()
ConnectionStatus(self.key).set(status)
if status == False:
pass
# TODO: do

def pre_save(self):
""" encrypt password if not already encrypted """
if self.password and not self.password.startswith('$pbkdf2'):
Expand Down
49 changes: 45 additions & 4 deletions zengine/messaging/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ def get_or_create_direct_channel(cls, initiator, receiver):
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()
Subscriber(channel=channel, user=initiator).save()
Subscriber(channel=channel, user=receiver).save()
return channel

def add_message(self, body, title=None, sender=None, url=None, typ=2, receiver=None):
Expand All @@ -95,6 +95,10 @@ def add_message(self, body, title=None, sender=None, url=None, typ=2, receiver=N
return Message(sender=sender, body=body, msg_title=title, url=url,
typ=typ, channel=self, receiver=receiver).save()

def get_last_messages(self):
# TODO: Refactor this with RabbitMQ Last Cached Messages exchange
return self.message_set.objects.filter()[:20]

@classmethod
def _connect_mq(cls):
if cls.connection is None or cls.connection.is_closed:
Expand Down Expand Up @@ -123,13 +127,13 @@ def post_creation(self):
self.create_exchange()


class Subscription(Model):
class Subscriber(Model):
"""
Permission model
"""

channel = Channel()
user = UserModel(reverse_name='channels')
user = UserModel(reverse_name='subscriptions')
is_muted = field.Boolean("Mute the channel")
inform_me = field.Boolean("Inform when I'm mentioned", default=True)
visible = field.Boolean("Show under user's channel list", default=True)
Expand All @@ -143,6 +147,10 @@ def _connect_mq(cls):
cls.connection, cls.channel = get_mq_connection()
return cls.channel

def unread_count(self):
# FIXME: track and return actual unread message count
return 0

def create_exchange(self):
"""
Creates user's private exchange
Expand Down Expand Up @@ -200,6 +208,32 @@ class Message(Model):
body = field.String("Body")
url = field.String("URL")

def get_actions_for(self, user):
actions = [
('Favorite', 'favorite_message')
]
if self.sender == user:
actions.extend([
('Delete', 'delete_message'),
('Edit', 'delete_message')
])
else:
actions.extend([
('Flag', 'flag_message')
])

def serialize_for(self, user):
return {
'content': self.body,
'type': self.typ,
'attachments': [attachment.serialize() for attachment in self.attachment_set],
'title': self.msg_title,
'sender_name': self.sender.full_name,
'sender_key': self.sender.key,
'key': self.key,
'actions': self.get_actions_for(user),
}

def __unicode__(self):
content = self.msg_title or self.body
return "%s%s" % (content[:30], '...' if len(content) > 30 else '')
Expand All @@ -225,6 +259,13 @@ class Attachment(Model):
channel = Channel()
message = Message()

def serialize(self):
return {
'description': self.description,
'file_name': self.name,
'url': "%s%s" % (settings.S3_PUBLIC_URL, self.file)
}

def __unicode__(self):
return self.name

Expand Down
71 changes: 51 additions & 20 deletions zengine/messaging/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,18 @@
UserModel = get_object_from_path(settings.USER_MODEL)



def create_message(current):
"""
Creates a message for the given channel.
.. code-block:: python
# request:
# request:
{
'view':'_zops_create_message',
'message': {
'channel': "code_name of the channel",
'receiver': "Key of receiver. Can be blank for non-direct messages",
'client_id': "Client side unique id for referencing this message",
'receiver': key, " of receiver. Should be set only for direct messages",
'title': "Title of the message. Can be blank.",
'body': "Message body.",
'type': zengine.messaging.model.MSG_TYPES,
Expand All @@ -38,7 +36,7 @@ def create_message(current):
}]}
# response:
{
'msg_key': "Key of the just created message object",
'msg_key': key, # of the just created message object,
}
"""
Expand All @@ -53,27 +51,29 @@ def create_message(current):
Attachment(channel=ch, msg=msg_obj, name=atch['name'], file=atch['content'],
description=atch['description'], typ=typ).save()

def _dedect_file_type(current, name, content):
# TODO: Attachment type detection

def _dedect_file_type(name, content):
# FIXME: Implement attachment type detection
return 1 # Return as Document for now

def show_public_channel(current):

def show_channel(current):
"""
Initial display of channel content.
Returns chanel description, no of members, last 20 messages etc.
Returns channel description, members, no of members, last 20 messages etc.
.. code-block:: python
# request:
{
'view':'_zops_show_public_channel',
'channel_key': "Key of the requested channel"
'channel_key': key,
}
# response:
{
'channel_key': "key of channel",
'channel_key': key,
'description': string,
'no_of_members': int,
'member_list': [
Expand All @@ -83,37 +83,68 @@ def show_public_channel(current):
}],
'last_messages': [
{'content': string,
'key': string,
'actions':[
{'title': string,
'cmd': string
}
]
'title': string,
'channel_key': key,
'sender_name': string,
'sender_key': key,
'type': int,
'key': key,
'actions':[('name_string', 'cmd_string'),]
}
]
}
"""


ch_key = current.input['channel_key']
ch = Channel.objects.get(ch_key)
current.output = {'channel_key': ch_key,
'description': ch.description,
'no_of_members': len(ch.subscriber_set),
'member_list': [{'name': sb.user.full_name,
'is_online': sb.user.is_online(),
'avatar_url': sb.user.get_avatar_url()
} for sb in ch.subscriber_set],
'last_messages': [msg.serialize_for(current.user)
for msg in ch.get_last_messages()]
}

def mark_offline_user(current):
current.user.is_online(False)

def list_channels(current):
pass
return [
{'name': sbs.channel.name,
'key': sbs.channel.key,
'unread': sbs.unread_count()} for sbs in
current.user.subscriptions]


def create_public_channel(current):
pass


def create_direct_channel(current):
"""
Create a One-To-One channel for current user and selected user.
"""
pass


def create_broadcast_channel(current):
"""
Create a One-To-One channel for current user and selected user.
"""
pass


def find_message(current):
pass


def delete_message(current):
pass


def edit_message(current):
pass
3 changes: 2 additions & 1 deletion zengine/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@
'dashboard': 'zengine.views.menu.Menu',
'ping': 'zengine.views.dev_utils.Ping',
'_zops_create_message': 'zengine.messaging.views.create_message',

'mark_offline_user': 'zengine.messaging.views.mark_offline_user',
'show_channel': 'zengine.messaging.views.show_channel',
}

if DEBUG:
Expand Down
7 changes: 7 additions & 0 deletions zengine/tornado_server/queue_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,15 @@ def register_websocket(self, sess_id, ws):
self.websockets[sess_id] = ws
channel = self.create_out_channel(sess_id)

def inform_disconnection(self, sess_id):
self.websockets[sess_id].write_message({
'view': 'mark_offline_user',
'sess_id': sess_id
})

def unregister_websocket(self, sess_id):
try:
self.inform_disconnection(sess_id)
del self.websockets[sess_id]
except KeyError:
log.exception("Non-existent websocket")
Expand Down
4 changes: 4 additions & 0 deletions zengine/views/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ def _do_binding(self):
# routing_key="#"
)

def _user_is_online(self):
self.current.user.is_online(True)

def do_view(self):
"""
Authenticate user with given credentials.
Expand All @@ -79,6 +82,7 @@ def do_view(self):
self.current.input['password'])
self.current.task_data['login_successful'] = auth_result
if auth_result:
self._user_is_online()
self._do_binding()
user_sess = UserSessionID(self.current.user_id)
old_sess_id = user_sess.get()
Expand Down

0 comments on commit 4040086

Please sign in to comment.