class ThreadedComment(Comment): title = models.TextField(_('Title'), blank=True) parent = models.ForeignKey('self', null=True, blank=True, default=None, related_name='children', verbose_name=_('Parent')) last_child = models.ForeignKey('self', null=True, blank=True, verbose_name=_('Last child')) tree_path = models.CharField(_('Tree path'), editable=False, db_index=True, max_length=255) rank = models.IntegerField(_('Rank'), null=True) objects = CommentManager() def _get_depth(self): return len(self.tree_path.split(PATH_SEPARATOR)) depth = property(_get_depth) def _root_id(self): return int(self.tree_path.split(PATH_SEPARATOR)[0]) root_id = property(_root_id) def _root_path(self): return ThreadedComment.objects.filter( pk__in=self.tree_path.split(PATH_SEPARATOR)[:-1]) root_path = property(_root_path) def save(self, *args, **kwargs): skip_tree_path = kwargs.pop('skip_tree_path', False) super(ThreadedComment, self).save(*args, **kwargs) if skip_tree_path: return None tree_path = unicode(self.pk).zfill(PATH_DIGITS) if self.parent: tree_path = PATH_SEPARATOR.join((self.parent.tree_path, tree_path)) self.parent.last_child = self ThreadedComment.objects.filter(pk=self.parent_id).update( last_child=self) self.tree_path = tree_path ThreadedComment.objects.filter(pk=self.pk).update( tree_path=self.tree_path) class Meta(object): ordering = ('tree_path', 'rank') db_table = 'threadedcomments_comment' verbose_name = _('Threaded comment') verbose_name_plural = _('Threaded comments')
class CustomComment(DatasetMixin, Comment): _dataset = CommentDataset date_updated = models.DateTimeField(default=lambda *args: timezone.now()) objects = CommentManager() @classmethod def load_comments(cls, app, model, pk, offset=0, size=10): return @classmethod def post_comment(cls, app, model, pk, content): return
class ThreadedComment(MPTTModel, Comment): """ Threaded comments with MPTT """ parent = TreeForeignKey( 'self', related_name='children', null=True, blank=True, verbose_name=_('reply in comment')) objects = CommentManager() tree = TreeManager() class MPTTMeta: """ Comment MPTT's meta informations. """ order_insertion_by = ['submit_date']
class CustomComment(ThreadedComment): subscribe = models.BooleanField(default=False) objects = CommentManager() def save(self, send_notifications=True, *args, **kwargs): created = not self.pk super(CustomComment, self).save(*args, **kwargs) if created and notification_enabled() and send_notifications: self.send_admin_notifications() if not moderation_enabled(): self.send_subscriptors_notifications() def send_admin_notifications(self): subject = _("New comment posted on '%s'") % self.content_object message = self.get_as_text() if moderation_enabled(): url = "http://%s%s" % (self.site.domain, reverse('comments-approve', args=(self.id, ))) managers_message = _("This comment is moderated!\nYou may approve it " \ "on the following url: %s\n\n") % url + message else: managers_message = message mail_managers(subject, managers_message, fail_silently=True) # Send mail to suscribed users of the tree path def send_subscriptors_notifications(self): subject = _("New comment posted on '%s'") % self.content_object message = self.get_as_text() comments = CustomComment.objects.filter(id=self.root_path, subscribe=True) if comments: messages = [(subject, message, settings.DEFAULT_FROM_EMAIL, [comment.userinfo["email"]]) for comment in comments] send_mass_mail(messages, fail_silently=True) class Meta: verbose_name = _("comment") verbose_name_plural = _("comments")
class Comment(BaseCommentAbstractModel): """ A user comment about some object. """ # Who posted this comment? If ``user`` is set then it was an authenticated # user; otherwise at least user_name should have been set and the comment # was posted by a non-authenticated user. user = models.ForeignKey(User, verbose_name=_('user'), blank=True, null=True, related_name="%(class)s_comments") user_name = models.CharField(_("user's name"), max_length=50, blank=True) user_email = models.EmailField(_("user's email address"), blank=True) user_url = models.URLField(_("user's URL"), blank=True) comment = models.TextField(_('comment'), max_length=COMMENT_MAX_LENGTH) # Metadata about the comment submit_date = models.DateTimeField(_('date/time submitted'), default=None) ip_address = models.IPAddressField(_('IP address'), blank=True, null=True) is_public = models.BooleanField(_('is public'), default=True, help_text=_('Uncheck this box to make the comment effectively ' \ 'disappear from the site.')) is_removed = models.BooleanField(_('is removed'), default=False, help_text=_('Check this box if the comment is inappropriate. ' \ 'A "This comment has been removed" message will ' \ 'be displayed instead.')) # Manager objects = CommentManager() class Meta: db_table = "django_comments" ordering = ('submit_date', ) permissions = [("can_moderate", "Can moderate comments")] verbose_name = _('comment') verbose_name_plural = _('comments') def __unicode__(self): return "%s: %s..." % (self.name, self.comment[:50]) def save(self, *args, **kwargs): if self.submit_date is None: self.submit_date = timezone.now() super(Comment, self).save(*args, **kwargs) def _get_userinfo(self): """ Get a dictionary that pulls together information about the poster safely for both authenticated and non-authenticated comments. This dict will have ``name``, ``email``, and ``url`` fields. """ if not hasattr(self, "_userinfo"): self._userinfo = { "name": self.user_name, "email": self.user_email, "url": self.user_url } if self.user_id: u = self.user if u.email: self._userinfo["email"] = u.email # If the user has a full name, use that for the user name. # However, a given user_name overrides the raw user.username, # so only use that if this comment has no associated name. if u.get_full_name(): self._userinfo["name"] = self.user.get_full_name() elif not self.user_name: self._userinfo["name"] = u.username return self._userinfo userinfo = property(_get_userinfo, doc=_get_userinfo.__doc__) def _get_name(self): return self.userinfo["name"] def _set_name(self, val): if self.user_id: raise AttributeError(_("This comment was posted by an authenticated "\ "user and thus the name is read-only.")) self.user_name = val name = property(_get_name, _set_name, doc="The name of the user who posted this comment") def _get_email(self): return self.userinfo["email"] def _set_email(self, val): if self.user_id: raise AttributeError(_("This comment was posted by an authenticated "\ "user and thus the email is read-only.")) self.user_email = val email = property(_get_email, _set_email, doc="The email of the user who posted this comment") def _get_url(self): return self.userinfo["url"] def _set_url(self, val): self.user_url = val url = property(_get_url, _set_url, doc="The URL given by the user who posted this comment") def get_absolute_url(self, anchor_pattern="#c%(id)s"): return self.get_content_object_url() + (anchor_pattern % self.__dict__) def get_as_text(self): """ Return this comment as plain text. Useful for emails. """ d = { 'user': self.user or self.name, 'date': self.submit_date, 'comment': self.comment, 'domain': self.site.domain, 'url': self.get_absolute_url() } return _( 'Posted by %(user)s at %(date)s\n\n%(comment)s\n\nhttp://%(domain)s%(url)s' ) % d
class ThreadedComment(MPTTModel, BaseCommentAbstractModel): # Copied from comments.Comment user = models.ForeignKey(User, verbose_name=_('user'), blank=True, null=True, related_name="%(class)s_comments") comment = models.TextField(_('comment'), max_length=COMMENT_MAX_LENGTH) submit_date = models.DateTimeField(_('date/time submitted'), default=None) ip_address = models.IPAddressField(_('IP address'), blank=True, null=True) is_public = models.BooleanField( _('is public'), default=True, help_text=_('Uncheck this box to make the comment effectively ' 'disappear from the site.')) is_removed = models.BooleanField( _('is removed'), default=False, help_text=_('Check this box if the comment is inappropriate. ' 'A "This comment has been removed" message will ' 'be displayed instead.')) objects = CommentManager() class Meta: ordering = ( 'tree_id', 'submit_date', ) def __unicode__(self): if self.is_removed: return u"a deleted comment" try: name = self.user.username except Exception: name = None return u"%s: %s..." % (name, self.comment[:50]) def save(self, *args, **kwargs): if self.submit_date is None: self.submit_date = timezone.now() # Forbid more than 2 levels if self.parent_id is not None: while self.parent.get_level() > 0: self.parent = self.parent.parent super(ThreadedComment, self).save(*args, **kwargs) def get_absolute_url(self, anchor_pattern="#comment-{id}"): url_base = self.get_content_object_url() return url_base + anchor_pattern.format(**self.__dict__) def get_reply_url(self, anchor_pattern="#reply-comment-{id}"): url_base = self.get_content_object_url() return url_base + anchor_pattern.format(**self.__dict__) def get_toplevel(self): if self.get_level() == 0: return self return self.parent.get_toplevel() # My stuff parent = TreeForeignKey('self', null=True, blank=True, related_name='children') post_to_facebook = models.BooleanField(default=False) class MPTTMeta: # comments on one level will be ordered by date of creation order_insertion_by = ['submit_date']
from openPLM.plmapp.models.document import * from openPLM.plmapp.models.history import * from openPLM.plmapp.models.link import * # monkey patch Comment models to select related fields from django.contrib.comments.models import Comment from django.contrib.comments.managers import CommentManager class CommentManager(CommentManager): def get_query_set(self): return (super(CommentManager, self).get_query_set().select_related( 'user', 'user__profile')) Comment.add_to_class('objects', CommentManager()) # import_models should be the last function def import_models(force_reload=False): u""" Imports recursively all modules in directory *plmapp/customized_models* """ MODELS_DIR = "customized_models" IMPORT_ROOT = "openPLM.plmapp.%s" % MODELS_DIR if __name__ != "openPLM.plmapp.models": # this avoids to import models twice return if force_reload or not hasattr(import_models, "done"):
def filter(self, *args, **kwargs): "small optimization" return CommentManager.filter(self, *args, **kwargs).select_related("user")
class ThreadedComment(Comment): title = models.TextField(_('Title'), blank=True) parent = models.ForeignKey('self', null=True, blank=True, default=None, related_name='children', verbose_name=_('Parent')) last_child = models.ForeignKey('self', null=True, blank=True, verbose_name=_('Last child')) tree_path = models.TextField(_('Tree path'), editable=False) #db_index=True) objects = CommentManager() __like = None __like_users = None __nolike = None __nolike_users = None def _get_depth(self): return len(self.tree_path.split(PATH_SEPARATOR)) depth = property(_get_depth) def _root_id(self): return int(self.tree_path.split(PATH_SEPARATOR)[0]) root_id = property(_root_id) def _root_path(self): return ThreadedComment.objects.filter( pk__in=self.tree_path.split(PATH_SEPARATOR)[:-1]) root_path = property(_root_path) def save(self, *args, **kwargs): skip_tree_path = kwargs.pop('skip_tree_path', False) super(ThreadedComment, self).save(*args, **kwargs) if skip_tree_path: return None tree_path = unicode(self.pk).zfill(PATH_DIGITS) if self.parent: tree_path = PATH_SEPARATOR.join((self.parent.tree_path, tree_path)) self.parent.last_child = self ThreadedComment.objects.filter(pk=self.parent_id).update( last_child=self) self.tree_path = tree_path ThreadedComment.objects.filter(pk=self.pk).update( tree_path=self.tree_path) def __get_relate(self): relate_list = self.relate.select_related().all() self.__like = [] self.__nolike = [] for r in relate_list: if r.relate == '+': self.__like.append(r) elif r.relate == '-': self.__nolike.append(r) def __get_like(self): if self.__like is None: self.__get_relate() return self.__like like = property(__get_like) def __get_like_users(self): if self.__like_users is None: self.__like_users = [l.user for l in self.like] return self.__like_users like_users = property(__get_like_users) def __get_nolike(self): if self.__nolike is None: self.__get_relate() return self.__nolike nolike = property(__get_nolike) def __get_nolike_users(self): if self.__nolike_users is None: self.__nolike_users = [l.user for l in self.nolike] return self.__nolike_users nolike_users = property(__get_nolike_users) class Meta(object): ordering = ('tree_path', ) db_table = 'threadedcomments_comment' verbose_name = _('Threaded comment') verbose_name_plural = _('Threaded comments')
class ThreadedComment(Comment): title = models.TextField(_('Title'), blank=True) parent = models.ForeignKey('self', null=True, blank=True, default=None, related_name='children', verbose_name=_('Parent')) last_child = models.ForeignKey('self', null=True, blank=True, on_delete=models.SET_NULL, verbose_name=_('Last child')) tree_path = models.TextField(_('Tree path'), editable=False, db_index=True) objects = CommentManager() @property def depth(self): return len(self.tree_path.split(PATH_SEPARATOR)) @property def root_id(self): return int(self.tree_path.split(PATH_SEPARATOR)[0]) @property def root_path(self): return ThreadedComment.objects.filter( pk__in=self.tree_path.split(PATH_SEPARATOR)[:-1]) def save(self, *args, **kwargs): skip_tree_path = kwargs.pop('skip_tree_path', False) super(ThreadedComment, self).save(*args, **kwargs) if skip_tree_path: return None tree_path = unicode(self.pk).zfill(PATH_DIGITS) if self.parent: tree_path = PATH_SEPARATOR.join((self.parent.tree_path, tree_path)) self.parent.last_child = self ThreadedComment.objects.filter(pk=self.parent_id).update( last_child=self) self.tree_path = tree_path ThreadedComment.objects.filter(pk=self.pk).update( tree_path=self.tree_path) def delete(self, *args, **kwargs): # Fix last child on deletion. if self.parent_id: try: prev_child_id = ThreadedComment.objects \ .filter(parent=self.parent_id) \ .exclude(pk=self.pk) \ .order_by('-submit_date') \ .values_list('pk', flat=True)[0] except IndexError: prev_child_id = None ThreadedComment.objects.filter(pk=self.parent_id).update( last_child=prev_child_id) super(ThreadedComment, self).delete(*args, **kwargs) class Meta(object): ordering = ('tree_path', ) db_table = 'threadedcomments_comment' verbose_name = _('Threaded comment') verbose_name_plural = _('Threaded comments')
class CommentWithRating(Comment): rating = models.IntegerField() objects = CommentManager()