PageRenderTime 35ms CodeModel.GetById 2ms app.highlight 26ms RepoModel.GetById 1ms app.codeStats 1ms

/jchat/models.py

http://django-jchat.googlecode.com/
Python | 129 lines | 112 code | 3 blank | 14 comment | 2 complexity | d35edd473331cdaef513715a21a41e41 MD5 | raw file
  1# -*- encoding: UTF-8 -*-
  2'''
  3Models for jchat application.
  4
  5Let's try to make this as modular as possible, no strings attached
  6
  7THIS IMPLEMENTATION HAS A TERRIBLE PROBLEM, NO VALIDATION IS DONE WETHER THE USER CAN OR NOT SAY SOMETHING HERE, SO 'GHOST' USERS COULD BE SENDING MESSAGES TO A CHAT ROOM...
  8THE OPTIMAL SOLUTION IS TO BIND THE CHAT ROOM WITH THE DIFFERENT OBJECTS THAT CAN USE IT, THAT IS, CREATE A FK FROM THE OBJECTS TO THE CHATROOM AND USE THE OBJECT ITSELF AS A VALIDATOR AND GATEWAY TO THE CHATROOM.
  9IN OTHER WAYS... IMPLEMENT A MODEL FOR CONNECTED USERS ASAP (I accept suggestions)
 10
 11For more hardcore uses... a dedicated and specialized application should be better:
 12@see: http://en.wikipedia.org/wiki/Comet_(programming)
 13
 14@author: Federico C??ceres <fede.caceres@gmail.com>
 15'''
 16
 17from django.db import models
 18from django.contrib.auth.models import User
 19from django.contrib.contenttypes.models import ContentType, ContentTypeManager 
 20from django.contrib.contenttypes import generic 
 21from datetime import datetime
 22
 23
 24class RoomManager(models.Manager):
 25    '''Custom model manager for rooms, this is used for "table-level" operations.
 26    All methods defined here can be invoked through the Room.objects class.
 27    @see: http://docs.djangoproject.com/en/1.0/topics/db/managers/#topics-db-managers
 28    Also see GenericTypes from the contenttypes django app!
 29    @see: http://docs.djangoproject.com/en/1.0/ref/contrib/contenttypes/''' 
 30    def create(self, object):
 31        '''Creates a new chat room and registers it to the calling object'''
 32        r = self.model(content_object=object)
 33        r.save()
 34        return r
 35        
 36    def get_for_object(self, object):
 37        '''Try to get a room related to the object passed.'''
 38        return self.get(content_type=ContentType.objects.get_for_model(object), object_id=object.pk)
 39
 40    def get_or_create(self, object):
 41        '''Save us from the hassle of validating the return value of get_for_object and create a room if none exists'''
 42        try:
 43            return self.get_for_object(object)
 44        except Room.DoesNotExist:
 45            return self.create(object)
 46
 47class Room(models.Model):
 48    '''Representation of a generic chat room'''
 49    content_type = models.ForeignKey(ContentType, blank=True, null=True) # to what kind of object is this related
 50    object_id = models.PositiveIntegerField(blank=True, null=True) # to which instace of the aforementioned object is this related
 51    content_object = generic.GenericForeignKey('content_type','object_id') # use both up, USE THIS WHEN INSTANCING THE MODEL
 52    created = models.DateTimeField(default=datetime.now())
 53    comment = models.TextField(blank=True, null=True)
 54    objects = RoomManager() # custom manager
 55    
 56    def __add_message(self, type, sender, message=None):
 57        '''Generic function for adding a message to the chat room'''
 58        m = Message(room=self, type=type, author=sender, message=message)
 59        m.save()
 60        return m
 61    
 62    def say(self, sender, message):
 63        '''Say something in to the chat room'''
 64        return self.__add_message('m', sender, message)
 65    
 66    def join(self, user):
 67        '''A user has joined'''
 68        return self.__add_message('j', user)
 69    
 70    def leave(self, user):
 71        '''A user has leaved'''
 72        return self.__add_message('l', user)
 73    
 74    def messages(self, after_pk=None, after_date=None):
 75        '''List messages, after the given id or date'''
 76        m = Message.objects.filter(room=self)
 77        if after_pk:
 78            m = m.filter(pk__gt=after_pk)
 79        if after_date:
 80            m = m.filter(timestamp__gte=after_date)
 81        return m.order_by('pk')
 82    
 83    def last_message_id(self):
 84        '''Return last message sent to room'''
 85        m = Message.objects.filter(room=self).order_by('-pk')
 86        if m:
 87            return m[0].id
 88        else:
 89            return 0
 90    
 91    def __unicode__(self):
 92        return 'Chat for %s %d' % (self.content_type, self.object_id)
 93    
 94    class Meta:
 95        unique_together = (("content_type", "object_id"),)
 96
 97
 98MESSAGE_TYPE_CHOICES = (
 99    ('s','system'),
100    ('a','action'),
101    ('m', 'message'),
102    ('j','join'),
103    ('l','leave'),
104    ('n','notification')
105)
106
107
108class Message(models.Model):
109    '''A message that belongs to a chat room'''
110    room = models.ForeignKey(Room)
111    type = models.CharField(max_length=1, choices=MESSAGE_TYPE_CHOICES)
112    author = models.ForeignKey(User, related_name='author', blank=True, null=True)
113    message = models.CharField(max_length=255, blank=True, null=True)
114    timestamp = models.DateTimeField(auto_now=True)
115    
116    def __unicode__(self):
117        '''Each message type has a special representation, return that representation.
118        This will also be translator AKA i18l friendly.''' 
119        if self.type == 's':
120            return u'SYSTEM: %s' % self.message
121        if self.type == 'n':
122            return u'NOTIFICATION: %s' % self.message
123        elif self.type == 'j':
124            return 'JOIN: %s' % self.author
125        elif self.type == 'l':
126            return 'LEAVE: %s' % self.author
127        elif self.type == 'a':
128            return 'ACTION: %s > %s' % (self.author, self.message)
129        return self.message