models.py 6.41 KB
Newer Older
Skia's avatar
Skia committed
1 2 3 4 5 6 7 8 9
from django.db import models
from django.core import validators
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ValidationError
from django.db import IntegrityError, transaction
from django.core.urlresolvers import reverse
from django.utils import timezone

Skia's avatar
Skia committed
10 11 12
from datetime import datetime
import pytz

Skia's avatar
Skia committed
13
from core.models import User, MetaGroup, Group, SithFile
14
from club.models import Club
Skia's avatar
Skia committed
15 16 17 18 19 20 21 22 23

class Forum(models.Model):
    """
    The Forum class, made as a tree to allow nice tidy organization
    """
    name = models.CharField(_('name'), max_length=64)
    description = models.CharField(_('description'), max_length=256, default="")
    is_category = models.BooleanField(_('is a category'), default=False)
    parent = models.ForeignKey('Forum', related_name='children', null=True, blank=True)
24 25
    owner_club = models.ForeignKey(Club, related_name="owned_forums", verbose_name=_("owner club"),
            default=settings.SITH_MAIN_CLUB_ID)
26 27 28 29 30
    edit_groups = models.ManyToManyField(Group, related_name="editable_forums", blank=True,
            default=[settings.SITH_GROUP_OLD_SUBSCRIBERS_ID])
    view_groups = models.ManyToManyField(Group, related_name="viewable_forums", blank=True,
            default=[settings.SITH_GROUP_PUBLIC_ID])

31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
    def clean(self):
        self.check_loop()

    def save(self, *args, **kwargs):
        copy_rights = False
        if self.id is None:
            copy_rights = True
        super(Forum, self).save(*args, **kwargs)
        if copy_rights:
            self.copy_rights()

    def apply_rights_recursively(self):
        children = self.children.all()
        for c in children:
            c.copy_rights()
            c.apply_rights_recursively()

    def copy_rights(self):
        """Copy, if possible, the rights of the parent folder"""
        if self.parent is not None:
            self.owner_club = self.parent.owner_club
            self.edit_groups = self.parent.edit_groups.all()
            self.view_groups = self.parent.view_groups.all()
            self.save()

56
    def is_owned_by(self, user):
57 58 59 60 61 62
        if user.is_in_group(settings.SITH_GROUP_FORUM_ADMIN_ID):
            return True
        m = self.owner_club.get_membership_for(user)
        if m:
            return m.role > settings.SITH_MAXIMUM_FREE_ROLE
        return False
Skia's avatar
Skia committed
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87

    def check_loop(self):
        """Raise a validation error when a loop is found within the parent list"""
        objs = []
        cur = self
        while cur.parent is not None:
            if cur in objs:
                raise ValidationError(_('You can not make loops in forums'))
            objs.append(cur)
            cur = cur.parent

    def __str__(self):
        return "%s" % (self.name)

    def get_absolute_url(self):
        return reverse('forum:view_forum', kwargs={'forum_id': self.id})

    def get_parent_list(self):
        l = []
        p = self.parent
        while p is not None:
            l.append(p)
            p = p.parent
        return l

Skia's avatar
Skia committed
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
    def get_topic_number(self):
        number = self.topics.all().count()
        for c in self.children.all():
            number += c.get_topic_number()
        return number

    def get_last_message(self):
        last_msg = None
        for m in ForumMessage.objects.order_by('-id'):
            forum = m.topic.forum
            if self in (forum.get_parent_list() + [forum]):
                return m
                last_msg = m
        try:
            pass
        except: pass
        return last_msg

Skia's avatar
Skia committed
106 107 108 109 110 111
class ForumTopic(models.Model):
    forum = models.ForeignKey(Forum, related_name='topics')
    author = models.ForeignKey(User, related_name='forum_topics')
    description = models.CharField(_('description'), max_length=256, default="")

    class Meta:
Skia's avatar
Skia committed
112 113
        ordering = ['-id'] # TODO: add date message ordering

114 115 116 117 118 119 120 121 122
    def is_owned_by(self, user):
        return self.forum.is_owned_by(user) or user.id == self.author.id

    def can_be_edited_by(self, user):
        return user.can_edit(self.forum)

    def can_be_viewed_by(self, user):
        return user.can_view(self.forum)

Skia's avatar
Skia committed
123 124
    def __str__(self):
        return "%s" % (self.title)
Skia's avatar
Skia committed
125 126 127 128

    def get_absolute_url(self):
        return reverse('forum:view_topic', kwargs={'topic_id': self.id})

129 130 131 132
    @property
    def title(self):
        return self.messages.order_by('date').first().title

Skia's avatar
Skia committed
133 134
class ForumMessage(models.Model):
    """
135
    "A ForumMessage object represents a message in the forum" -- Cpt. Obvious
Skia's avatar
Skia committed
136 137 138 139 140 141
    """
    topic = models.ForeignKey(ForumTopic, related_name='messages')
    author = models.ForeignKey(User, related_name='forum_messages')
    title = models.CharField(_("title"), default="", max_length=64, blank=True)
    message = models.TextField(_("message"), default="")
    date = models.DateTimeField(_('date'), default=timezone.now)
Skia's avatar
Skia committed
142
    readers = models.ManyToManyField(User, related_name="read_messages", verbose_name=_("readers"))
Skia's avatar
Skia committed
143 144

    class Meta:
Skia's avatar
Skia committed
145
        ordering = ['id']
Skia's avatar
Skia committed
146

Skia's avatar
Skia committed
147 148 149
    def __str__(self):
        return "%s" % (self.title)

150 151 152 153
    def is_owned_by(self, user):
        return self.topic.is_owned_by(user) or user.id == self.author.id

    def can_be_edited_by(self, user):
Skia's avatar
Skia committed
154
        return user.is_owner(self.topic)
155 156 157 158

    def can_be_viewed_by(self, user):
        return user.can_view(self.topic)

Skia's avatar
Skia committed
159 160 161
    def can_be_moderated_by(self, user):
        return user.is_in_group(settings.SITH_GROUP_FORUM_ADMIN_ID)

Skia's avatar
Skia committed
162
    def get_absolute_url(self):
Skia's avatar
Skia committed
163 164 165 166 167
        return self.topic.get_absolute_url() + "#first_unread"

    def mark_as_read(self, user):
        self.readers.add(user)

Skia's avatar
Skia committed
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
    def is_deleted(self):
        meta = self.metas.exclude(action="EDIT").order_by('-date').first()
        if meta:
            return meta.action == "DELETE"
        return False

MESSAGE_META_ACTIONS = [
        ('EDIT', _("Message edited by")),
        ('DELETE', _("Message deleted by")),
        ('UNDELETE', _("Message undeleted by")),
        ]

class ForumMessageMeta(models.Model):
    user = models.ForeignKey(User, related_name="forum_message_metas")
    message = models.ForeignKey(ForumMessage, related_name="metas")
    date = models.DateTimeField(_('date'), default=timezone.now)
    action = models.CharField(_("action"), choices=MESSAGE_META_ACTIONS, max_length=16)

Skia's avatar
Skia committed
186 187 188 189
class ForumUserInfo(models.Model):
    user = models.OneToOneField(User, related_name="_forum_infos")
    last_read_date = models.DateTimeField(_('last read date'), default=datetime(year=settings.SITH_SCHOOL_START_YEAR,
        month=1, day=1, tzinfo=pytz.UTC))
Skia's avatar
Skia committed
190