Files
zulip/zephyr/models.py
Jessica McKellar f52ec24926 For now, compose zephyrs to usernames.
We'll eventually need to normalize emails, autocompleted names,
etc. to one entity we use when talking to the server about senders and
personals recipients, but for now since we've hardcoded usernames
everywhere, just use those.

(imported from commit 4a0e033b301b8dec55d97157eb4993982f6b2641)
2012-09-11 16:35:01 -04:00

228 lines
8.4 KiB
Python

from django.db import models
from django.contrib.auth.models import User
from django.db.models import Q
from django.db.models.signals import post_save
import hashlib
def get_display_recipient(recipient):
"""
recipient: an instance of Recipient.
returns: an appropriate string describing the recipient (the class
name, for a class, or the username, for a user).
"""
if recipient.type == Recipient.CLASS:
zephyr_class = ZephyrClass.objects.get(id=recipient.type_id)
return zephyr_class.name
elif recipient.type == Recipient.HUDDLE:
user_list = [UserProfile.objects.get(user=s.userprofile) for s in
Subscription.objects.filter(recipient=recipient)]
return [{'name': user.short_name} for user in user_list]
else:
user = User.objects.get(id=recipient.type_id)
return user.username
callback_table = {}
class Realm(models.Model):
domain = models.CharField(max_length=40)
def __repr__(self):
return "<Realm: %s %s>" % (self.domain, self.id)
def __str__(self):
return self.__repr__()
class UserProfile(models.Model):
user = models.OneToOneField(User)
full_name = models.CharField(max_length=100)
short_name = models.CharField(max_length=100)
pointer = models.IntegerField()
realm = models.ForeignKey(Realm)
# The user receives this message
def receive(self, message):
global callback_table
# Should also store in permanent database the receipt
um = UserMessage(user_profile=self, message=message)
um.save()
for cb in callback_table.get(self.user.id, []):
cb([message])
callback_table[self.user.id] = []
def add_callback(self, cb, last_received):
global callback_table
new_zephyrs = [um.message for um in
UserMessage.objects.filter(user_profile=self,
message__id__gt=last_received)]
if new_zephyrs:
return cb(new_zephyrs)
callback_table.setdefault(self.user.id, []).append(cb)
def __repr__(self):
return "<UserProfile: %s %s>" % (self.user.username, self.realm)
def __str__(self):
return self.__repr__()
def create_user_profile(user, realm, full_name, short_name):
"""When creating a new user, make a profile for him or her."""
if not UserProfile.objects.filter(user=user):
profile = UserProfile(user=user, pointer=-1, realm_id=realm.id,
full_name=full_name, short_name=short_name)
profile.save()
# Auto-sub to the ability to receive personals.
recipient = Recipient(type_id=profile.id, type=Recipient.PERSONAL)
recipient.save()
Subscription(userprofile=profile, recipient=recipient).save()
class ZephyrClass(models.Model):
name = models.CharField(max_length=30)
realm = models.ForeignKey(Realm)
def __repr__(self):
return "<ZephyrClass: %s>" % (self.name,)
def __str__(self):
return self.__repr__()
def create_zephyr_class(name, realm):
zephyr_class = ZephyrClass(name=name, realm=realm)
zephyr_class.save()
recipient = Recipient(type_id=zephyr_class.id, type=Recipient.CLASS)
recipient.save()
return (zephyr_class, recipient)
class Recipient(models.Model):
type_id = models.IntegerField()
type = models.PositiveSmallIntegerField()
# Valid types are {personal, class, huddle}
PERSONAL = 1
CLASS = 2
HUDDLE = 3
def type_name(self):
if self.type == self.PERSONAL:
return "personal"
elif self.type == self.CLASS:
return "class"
elif self.type == self.HUDDLE:
return "huddle"
else:
raise
def __repr__(self):
display_recipient = get_display_recipient(self)
return "<Recipient: %s (%d, %s)>" % (display_recipient, self.type_id, self.type)
class Zephyr(models.Model):
sender = models.ForeignKey(UserProfile)
recipient = models.ForeignKey(Recipient)
instance = models.CharField(max_length=30)
content = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def __repr__(self):
display_recipient = get_display_recipient(self.recipient)
return "<Zephyr: %s / %s / %r>" % (display_recipient, self.instance, self.sender)
def __str__(self):
return self.__repr__()
def to_dict(self):
return {'id' : self.id,
'sender' : self.sender.user.username,
'sender_email' : self.sender.user.email,
'sender_name' : self.sender.full_name,
'type' : self.recipient.type_name(),
'display_recipient': get_display_recipient(self.recipient),
'instance' : self.instance,
'content' : self.content,
'gravatar_hash' : hashlib.md5("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + self.sender.user.username).hexdigest(),
}
class UserMessage(models.Model):
user_profile = models.ForeignKey(UserProfile)
message = models.ForeignKey(Zephyr)
# We're not using the archived field for now, but create it anyway
# since this table will be an unpleasant one to do schema changes
# on later
archived = models.BooleanField()
def __repr__(self):
display_recipient = get_display_recipient(self.message.recipient)
return "<UserMessage: %s / %s>" % (display_recipient, self.user_profile.user.username)
def send_zephyr(**kwargs):
zephyr = kwargs["instance"]
if zephyr.recipient.type == Recipient.PERSONAL:
recipients = UserProfile.objects.filter(Q(user=zephyr.recipient.type_id) | Q(user=zephyr.sender))
# For personals, you send out either 1 or 2 copies of the zephyr, for
# personals to yourself or to someone else, respectively.
assert((len(recipients) == 1) or (len(recipients) == 2))
elif (zephyr.recipient.type == Recipient.CLASS or
zephyr.recipient.type == Recipient.HUDDLE):
recipients = [UserProfile.objects.get(user=s.userprofile) for
s in Subscription.objects.filter(recipient=zephyr.recipient, active=True)]
else:
raise
for recipient in recipients:
recipient.receive(zephyr)
post_save.connect(send_zephyr, sender=Zephyr)
class Subscription(models.Model):
userprofile = models.ForeignKey(UserProfile)
recipient = models.ForeignKey(Recipient)
active = models.BooleanField(default=True)
def __repr__(self):
return "<Subscription: %r -> %r>" % (self.userprofile, self.recipient)
def __str__(self):
return self.__repr__()
class Huddle(models.Model):
# TODO: We should consider whether using
# CommaSeparatedIntegerField would be better.
huddle_hash = models.CharField(max_length=40)
def get_huddle(id_list):
id_list = sorted(set(id_list))
hash_key = ",".join(str(x) for x in id_list)
huddle_hash = hashlib.sha1(hash_key).hexdigest()
if Huddle.objects.filter(huddle_hash=huddle_hash):
return Huddle.objects.get(huddle_hash=huddle_hash)
else:
# since we don't have one, make a new huddle
huddle = Huddle(huddle_hash = huddle_hash)
huddle.save()
recipient = Recipient(type_id=huddle.id, type=Recipient.HUDDLE)
recipient.save()
# Add subscriptions
for uid in id_list:
s = Subscription(recipient = recipient,
userprofile = UserProfile.objects.get(id=uid))
s.save()
return huddle
# This is currently dead code since all the places where we used to
# use it now have faster implementations, but I expect this to be
# potentially useful for code in the future, so not deleting it yet.
def filter_by_subscriptions(zephyrs, user):
userprofile = UserProfile.objects.get(user=user)
subscribed_zephyrs = []
subscriptions = [sub.recipient for sub in
Subscription.objects.filter(userprofile=userprofile, active=True)]
for zephyr in zephyrs:
# If you are subscribed to the personal or class, or if you
# sent the personal, you can see the zephyr.
if (zephyr.recipient in subscriptions) or \
(zephyr.recipient.type == Recipient.PERSONAL and
zephyr.sender == userprofile):
subscribed_zephyrs.append(zephyr)
return subscribed_zephyrs