diff options
Diffstat (limited to 'app/lib/django_comments/abstracts.py')
-rw-r--r-- | app/lib/django_comments/abstracts.py | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/app/lib/django_comments/abstracts.py b/app/lib/django_comments/abstracts.py new file mode 100644 index 0000000..e74ea02 --- /dev/null +++ b/app/lib/django_comments/abstracts.py @@ -0,0 +1,183 @@ +from __future__ import unicode_literals + +from django.conf import settings +from django.contrib.contenttypes.fields import GenericForeignKey +from django.contrib.contenttypes.models import ContentType +from django.contrib.sites.models import Site +from django.apps import apps +from django.utils.html import mark_safe +from django.db import models +from django.utils import timezone +from six import python_2_unicode_compatible +from django.utils.translation import ugettext_lazy as _ +try: + from django.urls import reverse +except ImportError: + from django.core.urlresolvers import reverse # Django < 1.10 + +from .managers import CommentManager + +COMMENT_MAX_LENGTH = getattr(settings, 'COMMENT_MAX_LENGTH', 3000) + + +class BaseCommentAbstractModel(models.Model): + """ + An abstract base class that any custom comment models probably should + subclass. + """ + + # Content-object field + content_type = models.ForeignKey(ContentType, + verbose_name=_('content type'), + related_name="content_type_set_for_%(class)s", + on_delete=models.CASCADE) + object_pk = models.TextField(_('object ID')) + content_object = GenericForeignKey(ct_field="content_type", fk_field="object_pk") + + # Metadata about the comment + site = models.ForeignKey(Site, on_delete=models.CASCADE) + + class Meta: + abstract = True + + def get_content_object_url(self): + """ + Get a URL suitable for redirecting to the content object. + """ + return reverse( + "comments-url-redirect", + args=(self.content_type_id, self.object_pk) + ) + + def get_object_url(self): + ctype = self.content_type + object_pk = self.object_pk + model = apps.get_model(ctype.app_label, ctype.model) + target = model.objects.get(pk=object_pk) + return mark_safe("<a href='%s'>%s</a>" % (target.get_absolute_url(), target.title)) + get_object_url.short_description = "comment item" + +@python_2_unicode_compatible +class CommentAbstractModel(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(settings.AUTH_USER_MODEL, verbose_name=_('user'), + blank=True, null=True, related_name="%(class)s_comments", + on_delete=models.SET_NULL) + user_name = models.CharField(_("user's name"), max_length=50, blank=True) + # Explicit `max_length` to apply both to Django 1.7 and 1.8+. + user_email = models.EmailField(_("user's email address"), max_length=254, + 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, db_index=True) + ip_address = models.GenericIPAddressField(_('IP address'), unpack_ipv4=True, 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: + abstract = True + ordering = ('submit_date',) + permissions = [("can_moderate", "Can moderate comments")] + verbose_name = _('comment') + verbose_name_plural = _('comments') + + def __str__(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(CommentAbstractModel, 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"): + userinfo = { + "name": self.user_name, + "email": self.user_email, + "url": self.user_url + } + if self.user_id: + u = self.user + if u.email: + 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(): + userinfo["name"] = self.user.get_full_name() + elif not self.user_name: + userinfo["name"] = u.get_username() + self._userinfo = userinfo + 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 |