Exemple #1
0
class UserProperty(BaseModel):
    user = models.ForeignKey(User, related_name='properties')
    key = models.CharField(max_length=16)
    value = PickledObjectField()

    class Meta:
        app_label = 'forum'
        unique_together = ('user', 'key')

    def cache_key(self):
        return self._generate_cache_key("%s:%s" % (self.user.id, self.key))

    @classmethod
    def infer_cache_key(cls, querydict):
        if 'user' in querydict and 'key' in querydict:
            return cls._generate_cache_key(
                "%s:%s" % (querydict['user'].id, querydict['key']))

        return None
Exemple #2
0
class Node(BaseModel, NodeContent):
    __metaclass__ = NodeMetaClass

    node_type = models.CharField(max_length=16, default='node')
    parent = models.ForeignKey('Node', related_name='children', null=True)
    abs_parent = models.ForeignKey('Node',
                                   related_name='all_children',
                                   null=True)

    added_at = models.DateTimeField(default=datetime.datetime.now)
    score = models.IntegerField(default=0)

    state_string = models.TextField(default='')
    last_edited = models.ForeignKey('Action',
                                    null=True,
                                    unique=True,
                                    related_name="edited_node")

    last_activity_by = models.ForeignKey(User, null=True)
    last_activity_at = models.DateTimeField(null=True, blank=True)

    tags = models.ManyToManyField('Tag', related_name='%(class)ss')
    active_revision = models.OneToOneField('NodeRevision',
                                           related_name='active',
                                           null=True)

    extra = PickledObjectField()
    extra_ref = models.ForeignKey('Node', null=True)
    extra_count = models.IntegerField(default=0)

    marked = models.BooleanField(default=False)

    comment_count = DenormalizedField("children",
                                      node_type="comment",
                                      canceled=False)
    flag_count = DenormalizedField("flags")

    friendly_name = _("post")

    objects = NodeManager()

    def __unicode__(self):
        return self.headline

    @classmethod
    def _generate_cache_key(cls, key, group="node"):
        return super(Node, cls)._generate_cache_key(key, group)

    @classmethod
    def get_type(cls):
        return cls.__name__.lower()

    @property
    def leaf(self):
        leaf_cls = NodeMetaClass.types.get(self.node_type, None)

        if leaf_cls is None:
            return self

        leaf = leaf_cls()
        leaf.__dict__ = self.__dict__
        return leaf

    @property
    def nstate(self):
        state = self.__dict__.get('_nstate', None)

        if state is None:
            state = NodeStateDict(self)
            self._nstate = state

        return state

    @property
    def nis(self):
        nis = self.__dict__.get('_nis', None)

        if nis is None:
            nis = NodeStateQuery(self)
            self._nis = nis

        return nis

    @property
    def last_activity(self):
        try:
            return self.actions.order_by('-action_date')[0].action_date
        except:
            return self.last_seen

    @property
    def state_list(self):
        return [s.state_type for s in self.states.all()]

    @property
    def deleted(self):
        return self.nis.deleted

    @property
    def absolute_parent(self):
        if not self.abs_parent_id:
            return self

        return self.abs_parent

    @property
    def summary(self):
        content = strip_tags(self.html)[:SUMMARY_LENGTH]

        # Remove multiple spaces.
        content = re.sub(' +', ' ', content)

        # Remove line breaks. We don't need them at all.
        content = content.replace("\n", '')

        return content

    @models.permalink
    def get_revisions_url(self):
        return ('revisions', (), {'id': self.id})

    def update_last_activity(self, user, save=False, time=None):
        if not time:
            time = datetime.datetime.now()

        self.last_activity_by = user
        self.last_activity_at = time

        if self.parent:
            self.parent.update_last_activity(user, save=True, time=time)

        if save:
            self.save()

    def _create_revision(self, user, number, **kwargs):
        revision = NodeRevision(author=user,
                                revision=number,
                                node=self,
                                **kwargs)
        revision.save()
        return revision

    def create_revision(self, user, **kwargs):
        number = self.revisions.aggregate(
            last=models.Max('revision'))['last'] + 1
        revision = self._create_revision(user, number, **kwargs)
        self.activate_revision(user, revision)
        return revision

    def activate_revision(self, user, revision):
        self.title = revision.title
        self.tagnames = revision.tagnames

        self.body = self.rendered(revision.body)

        self.active_revision = revision
        self.update_last_activity(user)

        self.save()

    def get_active_users(self, active_users=None):
        if not active_users:
            active_users = set()

        active_users.add(self.author)

        for node in self.children.all():
            if not node.nis.deleted:
                node.get_active_users(active_users)

        return active_users

    def get_last_edited(self):
        if not self.last_edited:
            try:
                le = self.actions.exclude(
                    action_type__in=('voteup', 'votedown', 'flag'),
                    canceled=True).order_by('-action_date')[0]
                self.last_edited = le
                self.save()
            except:
                pass

        return self.last_edited

    def _list_changes_in_tags(self):
        dirty = self.get_dirty_fields()

        if not 'tagnames' in dirty:
            return None
        else:
            if self._original_state['tagnames']:
                old_tags = set(self._original_state['tagnames'].split())
            else:
                old_tags = set()
            new_tags = set(self.tagnames.split())

            return dict(current=list(new_tags),
                        added=list(new_tags - old_tags),
                        removed=list(old_tags - new_tags))

    def _last_active_user(self):
        return self.last_edited and self.last_edited.by or self.author

    def _process_changes_in_tags(self):
        tag_changes = self._list_changes_in_tags()

        if tag_changes is not None:
            for name in tag_changes['added']:
                try:
                    tag = Tag.objects.get(name=name)
                except Tag.DoesNotExist:
                    tag = Tag.objects.create(
                        name=name, created_by=self._last_active_user())

                if not self.nis.deleted:
                    tag.add_to_usage_count(1)
                    tag.save()

            if not self.nis.deleted:
                for name in tag_changes['removed']:
                    try:
                        tag = Tag.objects.get(name=name)
                        tag.add_to_usage_count(-1)
                        tag.save()
                    except:
                        pass

            return True

        return False

    def mark_deleted(self, action):
        self.nstate.deleted = action
        self.save()

        if action:
            for tag in self.tags.all():
                tag.add_to_usage_count(-1)
                tag.save()
        else:
            for tag in Tag.objects.filter(name__in=self.tagname_list()):
                tag.add_to_usage_count(1)
                tag.save()

    def delete(self, *args, **kwargs):
        for tag in self.tags.all():
            tag.add_to_usage_count(-1)
            tag.save()

        self.active_revision = None
        self.save()

        for n in self.children.all():
            n.delete()

        for a in self.actions.all():
            a.cancel()

        super(Node, self).delete(*args, **kwargs)

    def save(self, *args, **kwargs):
        if not self.id:
            self.node_type = self.get_type()
            super(BaseModel, self).save(*args, **kwargs)
            self.active_revision = self._create_revision(
                self.author,
                1,
                title=self.title,
                tagnames=self.tagnames,
                body=self.body)
            self.activate_revision(self.author, self.active_revision)
            self.update_last_activity(self.author, time=self.added_at)

        if self.parent_id and not self.abs_parent_id:
            self.abs_parent = self.parent.absolute_parent

        tags_changed = self._process_changes_in_tags()

        super(Node, self).save(*args, **kwargs)
        if tags_changed:
            self.tags = list(Tag.objects.filter(name__in=self.tagname_list()))

    class Meta:
        app_label = 'forum'
Exemple #3
0
class Action(BaseModel):
    user = models.ForeignKey('User', related_name="actions")
    real_user = models.ForeignKey('User', related_name="proxied_actions", null=True)
    ip   = models.CharField(max_length=16)
    node = models.ForeignKey('Node', null=True, related_name="actions")
    action_type = models.CharField(max_length=16)
    action_date = models.DateTimeField(default=datetime.datetime.now)

    extra = PickledObjectField()

    canceled = models.BooleanField(default=False)
    canceled_by = models.ForeignKey('User', null=True, related_name="canceled_actions")
    canceled_at = models.DateTimeField(null=True)
    canceled_ip = models.CharField(max_length=16)

    hooks = {}

    objects = ActionManager()

    @property
    def at(self):
        return self.action_date

    @property
    def by(self):
        return self.user

    def repute_users(self):
        pass

    def process_data(self, **data):
        pass

    def process_action(self):
        pass

    def cancel_action(self):
        pass

    @property
    def verb(self):
        return ""

    def describe(self, viewer=None):
        return self.__class__.__name__

    def get_absolute_url(self):
        if self.node:
            return self.node.get_absolute_url()
        else:
            return self.user.get_profile_url()

    def repute(self, user, value):
        repute = ActionRepute(action=self, user=user, value=value)
        repute.save()
        return repute

    def cancel_reputes(self):
        for repute in self.reputes.all():
            cancel = ActionRepute(action=self, user=repute.user, value=(-repute.value), by_canceled=True)
            cancel.save()

    def leaf(self):
        leaf_cls = ActionProxyMetaClass.types.get(self.action_type, None)

        if leaf_cls is None:
            return self

        leaf = leaf_cls()
        d = self._as_dict()
        leaf.__dict__.update(self._as_dict())
        l = leaf._as_dict()
        return leaf

    @classmethod
    def get_type(cls):
        return re.sub(r'action$', '', cls.__name__.lower())

    def save(self, data=None, threaded=True, *args, **kwargs):
        isnew = False

        if not self.id:
            self.action_type = self.__class__.get_type()
            isnew = True

        if data:
            self.process_data(**data)

        super(Action, self).save(*args, **kwargs)

        if isnew:
            if (self.node is None) or (not self.node.nis.wiki):
                self.repute_users()
            self.process_action()
            self.trigger_hooks(threaded, True)

        return self

    def delete(self, *args, **kwargs):
        self.cancel_action()
        super(Action, self).delete(*args, **kwargs)

    def cancel(self, user=None, ip=None):
        if not self.canceled:
            self.canceled = True
            self.canceled_at = datetime.datetime.now()
            self.canceled_by = (user is None) and self.user or user
            if ip:
                self.canceled_ip = ip
            self.save()
            self.cancel_reputes()
            self.cancel_action()
        #self.trigger_hooks(False)

    @classmethod
    def get_current(cls, **kwargs):
        kwargs['canceled'] = False

        try:
            return cls.objects.get(**kwargs)
        except cls.MultipleObjectsReturned:
            logging.error("Got multiple values for action %s with args %s", cls.__name__,
                          ", ".join(["%s='%s'" % i for i in kwargs.items()]))
            raise
        except cls.DoesNotExist:
            return None

    @classmethod
    def hook(cls, fn):
        if not Action.hooks.get(cls, None):
            Action.hooks[cls] = []

        Action.hooks[cls].append(fn)

    def trigger_hooks(self, threaded, new=True):
        from forum.models import CustomBadge
        CustomBadge.load_custom_badges()
        if threaded:
            thread = Thread(target=trigger_hooks, args=[self, Action.hooks, new])
            thread.setDaemon(True)
            thread.start()
        else:
            trigger_hooks(self, Action.hooks, new)

    class Meta:
        app_label = 'forum'