diff options
author | luxagraf <sng@luxagraf.net> | 2017-10-14 11:36:20 -0500 |
---|---|---|
committer | luxagraf <sng@luxagraf.net> | 2017-10-14 11:36:20 -0500 |
commit | bd1adb4927695ed0ce3ac94d90c68bd61e440275 (patch) | |
tree | f014fa16a64eb55e62ecb92c62a4e8186cd318a4 | |
parent | cbadfff80be33b4ec67da57585451884c6378380 (diff) |
updated comments app and added caption to photo list view
34 files changed, 114 insertions, 1924 deletions
diff --git a/app/lib/django_comments/__init__.py b/app/lib/django_comments/__init__.py index c233b74..e4c5943 100644 --- a/app/lib/django_comments/__init__.py +++ b/app/lib/django_comments/__init__.py @@ -2,8 +2,11 @@ from importlib import import_module from django.apps import apps from django.conf import settings -from django.core import urlresolvers from django.core.exceptions import ImproperlyConfigured +try: + from django.urls import reverse +except ImportError: + from django.core.urlresolvers import reverse # Django < 1.10 DEFAULT_COMMENTS_APP = 'django_comments' @@ -68,7 +71,7 @@ def get_form_target(): if get_comment_app_name() != DEFAULT_COMMENTS_APP and hasattr(get_comment_app(), "get_form_target"): return get_comment_app().get_form_target() else: - return urlresolvers.reverse("comments-post-comment") + return reverse("comments-post-comment") def get_flag_url(comment): @@ -78,7 +81,7 @@ def get_flag_url(comment): if get_comment_app_name() != DEFAULT_COMMENTS_APP and hasattr(get_comment_app(), "get_flag_url"): return get_comment_app().get_flag_url(comment) else: - return urlresolvers.reverse("comments-flag", args=(comment.id,)) + return reverse("comments-flag", args=(comment.id,)) def get_delete_url(comment): @@ -88,7 +91,7 @@ def get_delete_url(comment): if get_comment_app_name() != DEFAULT_COMMENTS_APP and hasattr(get_comment_app(), "get_delete_url"): return get_comment_app().get_delete_url(comment) else: - return urlresolvers.reverse("comments-delete", args=(comment.id,)) + return reverse("comments-delete", args=(comment.id,)) def get_approve_url(comment): @@ -98,4 +101,4 @@ def get_approve_url(comment): if get_comment_app_name() != DEFAULT_COMMENTS_APP and hasattr(get_comment_app(), "get_approve_url"): return get_comment_app().get_approve_url(comment) else: - return urlresolvers.reverse("comments-approve", args=(comment.id,)) + return reverse("comments-approve", args=(comment.id,)) diff --git a/app/lib/django_comments/abstracts.py b/app/lib/django_comments/abstracts.py index 8004204..4fbb94a 100644 --- a/app/lib/django_comments/abstracts.py +++ b/app/lib/django_comments/abstracts.py @@ -4,11 +4,14 @@ 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.core import urlresolvers from django.db import models from django.utils import timezone from django.utils.encoding 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 @@ -39,7 +42,7 @@ class BaseCommentAbstractModel(models.Model): """ Get a URL suitable for redirecting to the content object. """ - return urlresolvers.reverse( + return reverse( "comments-url-redirect", args=(self.content_type_id, self.object_pk) ) diff --git a/app/lib/django_comments/forms.py b/app/lib/django_comments/forms.py index c1324e9..7b7eafd 100644 --- a/app/lib/django_comments/forms.py +++ b/app/lib/django_comments/forms.py @@ -56,8 +56,6 @@ class CommentSecurityForm(forms.Form): def clean_timestamp(self): """Make sure the timestamp isn't too far (default is > 2 hours) in the past.""" ts = self.cleaned_data["timestamp"] - if time.time() - ts > DEFAULT_COMMENTS_TIMEOUT: - raise forms.ValidationError("Timestamp check failed") return ts def generate_security_data(self): @@ -105,7 +103,7 @@ class CommentDetailsForm(CommentSecurityForm): comment = forms.CharField(label=_('Comment'), widget=forms.Textarea, max_length=COMMENT_MAX_LENGTH) - def get_comment_object(self): + def get_comment_object(self, site_id=None): """ Return a new (unsaved) comment object based on the information in this form. Assumes that the form is already validated and will throw a @@ -118,7 +116,7 @@ class CommentDetailsForm(CommentSecurityForm): raise ValueError("get_comment_object may only be called on valid forms") CommentModel = self.get_comment_model() - new = CommentModel(**self.get_comment_create_data()) + new = CommentModel(**self.get_comment_create_data(site_id=site_id)) new = self.check_for_duplicate_comment(new) return new @@ -131,7 +129,7 @@ class CommentDetailsForm(CommentSecurityForm): """ return get_model() - def get_comment_create_data(self): + def get_comment_create_data(self, site_id=None): """ Returns the dict of data to be used to create a comment. Subclasses in custom comment apps that override get_comment_model can override this @@ -145,7 +143,7 @@ class CommentDetailsForm(CommentSecurityForm): user_url=self.cleaned_data["url"], comment=self.cleaned_data["comment"], submit_date=timezone.now(), - site_id=settings.SITE_ID, + site_id=site_id or getattr(settings, "SITE_ID", None), is_public=True, is_removed=False, ) diff --git a/app/lib/django_comments/locale/eo/LC_MESSAGES/django.mo b/app/lib/django_comments/locale/eo/LC_MESSAGES/django.mo Binary files differindex 3fb4031..bb2a28f 100644 --- a/app/lib/django_comments/locale/eo/LC_MESSAGES/django.mo +++ b/app/lib/django_comments/locale/eo/LC_MESSAGES/django.mo diff --git a/app/lib/django_comments/locale/eo/LC_MESSAGES/django.po b/app/lib/django_comments/locale/eo/LC_MESSAGES/django.po index ee10cd7..c03e004 100644 --- a/app/lib/django_comments/locale/eo/LC_MESSAGES/django.po +++ b/app/lib/django_comments/locale/eo/LC_MESSAGES/django.po @@ -2,13 +2,14 @@ # # Translators: # Translators: +# Nikolay Korotkiy <sikmir@gmail.com>, 2016 msgid "" msgstr "" "Project-Id-Version: django-contrib-comments\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-22 17:28+0200\n" -"PO-Revision-Date: 2015-06-22 15:43+0000\n" -"Last-Translator: Claude Paroz <claude@2xlibre.net>\n" +"POT-Creation-Date: 2016-02-10 09:06+0100\n" +"PO-Revision-Date: 2016-11-11 12:09+0000\n" +"Last-Translator: Nikolay Korotkiy <sikmir@gmail.com>\n" "Language-Team: Esperanto (http://www.transifex.com/django/django-contrib-comments/language/eo/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -74,7 +75,7 @@ msgstr "Lastaj komentoj ĉe %(site_name)s" #: forms.py:105 msgctxt "Person name" msgid "Name" -msgstr "" +msgstr "Nomo" #: forms.py:97 msgid "Email address" @@ -201,6 +202,11 @@ msgstr "komenta marko" msgid "comment flags" msgstr "komentaj markoj" +#: moderation.py:253 +#, python-format +msgid "[%(site)s] New comment posted on \"%(object)s\"" +msgstr "[%(site)s] Nova komento afiŝita \"%(object)s\"" + #: templates/comments/approve.html:4 msgid "Approve a comment" msgstr "Aprobi komenton" diff --git a/app/lib/django_comments/locale/ko/LC_MESSAGES/django.mo b/app/lib/django_comments/locale/ko/LC_MESSAGES/django.mo Binary files differindex 4e26b8b..727eedb 100644 --- a/app/lib/django_comments/locale/ko/LC_MESSAGES/django.mo +++ b/app/lib/django_comments/locale/ko/LC_MESSAGES/django.mo diff --git a/app/lib/django_comments/locale/ko/LC_MESSAGES/django.po b/app/lib/django_comments/locale/ko/LC_MESSAGES/django.po index 7984422..3b14d2b 100644 --- a/app/lib/django_comments/locale/ko/LC_MESSAGES/django.po +++ b/app/lib/django_comments/locale/ko/LC_MESSAGES/django.po @@ -3,15 +3,16 @@ # Translators: # Translators: # Jannis Leidel <jannis@leidel.info>, 2011 -# Jeong Seongtae <magno79@gmail.com>, 2016 +# Le Tartuffe <magno79@gmail.com>, 2016 +# Jiyoon, Ha <cryptography@konkuk.ac.kr>, 2016 # Yeonsu Bak <yeonsubak@gmail.com>, 2015 msgid "" msgstr "" "Project-Id-Version: django-contrib-comments\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-02-10 09:06+0100\n" -"PO-Revision-Date: 2016-07-12 17:53+0000\n" -"Last-Translator: Jeong Seongtae <magno79@gmail.com>\n" +"PO-Revision-Date: 2016-09-15 16:44+0000\n" +"Last-Translator: Jiyoon, Ha <cryptography@konkuk.ac.kr>\n" "Language-Team: Korean (http://www.transifex.com/django/django-contrib-comments/language/ko/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -85,7 +86,7 @@ msgstr "URL" #: forms.py:99 msgid "Comment" -msgstr "코멘트:" +msgstr "코멘트" #: forms.py:177 #, python-format diff --git a/app/lib/django_comments/locale/nl/LC_MESSAGES/django.mo b/app/lib/django_comments/locale/nl/LC_MESSAGES/django.mo Binary files differindex dbeef7f..3b05375 100644 --- a/app/lib/django_comments/locale/nl/LC_MESSAGES/django.mo +++ b/app/lib/django_comments/locale/nl/LC_MESSAGES/django.mo diff --git a/app/lib/django_comments/locale/nl/LC_MESSAGES/django.po b/app/lib/django_comments/locale/nl/LC_MESSAGES/django.po index b55d19b..fddd817 100644 --- a/app/lib/django_comments/locale/nl/LC_MESSAGES/django.po +++ b/app/lib/django_comments/locale/nl/LC_MESSAGES/django.po @@ -3,15 +3,16 @@ # Translators: # Translators: # go2people <admin@go2people.nl>, 2011 +# Evelijn Saaltink <evelijnsaaltink@gmail.com>, 2016 # Jannis Leidel <jannis@leidel.info>, 2011 # Tino de Bruijn <tinodb@gmail.com>, 2011 msgid "" msgstr "" "Project-Id-Version: django-contrib-comments\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-22 17:28+0200\n" -"PO-Revision-Date: 2015-06-22 15:43+0000\n" -"Last-Translator: Claude Paroz <claude@2xlibre.net>\n" +"POT-Creation-Date: 2016-02-10 09:06+0100\n" +"PO-Revision-Date: 2016-10-12 18:03+0000\n" +"Last-Translator: Evelijn Saaltink <evelijnsaaltink@gmail.com>\n" "Language-Team: Dutch (http://www.transifex.com/django/django-contrib-comments/language/nl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -77,7 +78,7 @@ msgstr "Laatste opmerkingen op %(site_name)s" #: forms.py:105 msgctxt "Person name" msgid "Name" -msgstr "" +msgstr "Naam" #: forms.py:97 msgid "Email address" @@ -204,6 +205,11 @@ msgstr "opmerking vlag" msgid "comment flags" msgstr "opmerking vlaggen" +#: moderation.py:253 +#, python-format +msgid "[%(site)s] New comment posted on \"%(object)s\"" +msgstr "[%(site)s] Nieuwe opmerking geplaatst op \"%(object)s\"" + #: templates/comments/approve.html:4 msgid "Approve a comment" msgstr "Een opmerking toestaan" @@ -281,8 +287,8 @@ msgstr "Toon voorbeeld van uw opmerking" #: templates/comments/preview.html:11 msgid "Please correct the error below" msgid_plural "Please correct the errors below" -msgstr[0] "" -msgstr[1] "" +msgstr[0] "Please correct the error below" +msgstr[1] "Herstel de fouten hieronder" #: templates/comments/preview.html:16 msgid "Post your comment" diff --git a/app/lib/django_comments/locale/sq/LC_MESSAGES/django.mo b/app/lib/django_comments/locale/sq/LC_MESSAGES/django.mo Binary files differindex c4206c5..085c1d8 100644 --- a/app/lib/django_comments/locale/sq/LC_MESSAGES/django.mo +++ b/app/lib/django_comments/locale/sq/LC_MESSAGES/django.mo diff --git a/app/lib/django_comments/locale/sq/LC_MESSAGES/django.po b/app/lib/django_comments/locale/sq/LC_MESSAGES/django.po index d7f42d0..b50e3b5 100644 --- a/app/lib/django_comments/locale/sq/LC_MESSAGES/django.po +++ b/app/lib/django_comments/locale/sq/LC_MESSAGES/django.po @@ -3,13 +3,13 @@ # Translators: # Translators: # Besnik <besnik@programeshqip.org>, 2011 -# Besnik <besnik@programeshqip.org>, 2015 +# Besnik <besnik@programeshqip.org>, 2015-2016 msgid "" msgstr "" "Project-Id-Version: django-contrib-comments\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-22 17:28+0200\n" -"PO-Revision-Date: 2015-11-25 08:30+0000\n" +"POT-Creation-Date: 2016-02-10 09:06+0100\n" +"PO-Revision-Date: 2016-10-11 21:34+0000\n" "Last-Translator: Besnik <besnik@programeshqip.org>\n" "Language-Team: Albanian (http://www.transifex.com/django/django-contrib-comments/language/sq/)\n" "MIME-Version: 1.0\n" @@ -203,6 +203,11 @@ msgstr "shenjë komenti" msgid "comment flags" msgstr "shenja komenti" +#: moderation.py:253 +#, python-format +msgid "[%(site)s] New comment posted on \"%(object)s\"" +msgstr "[%(site)s] Koment i ri i postuar te \"%(object)s\"" + #: templates/comments/approve.html:4 msgid "Approve a comment" msgstr "Miratoni një koment" diff --git a/app/lib/django_comments/moderation.py b/app/lib/django_comments/moderation.py index f95e8ab..3e5c412 100644 --- a/app/lib/django_comments/moderation.py +++ b/app/lib/django_comments/moderation.py @@ -56,12 +56,11 @@ class. import datetime -from django import VERSION from django.conf import settings from django.contrib.sites.shortcuts import get_current_site from django.core.mail import send_mail from django.db.models.base import ModelBase -from django.template import Context, loader +from django.template import loader from django.utils import timezone from django.utils.translation import ugettext as _ @@ -254,7 +253,7 @@ class CommentModerator(object): 'site': get_current_site(request).name, 'object': content_object, } - message = t.render(Context(c) if VERSION < (1, 8) else c) + message = t.render(c) send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, recipient_list, fail_silently=True) diff --git a/app/lib/django_comments/templatetags/comments.py b/app/lib/django_comments/templatetags/comments.py index 75e5a0b..9b2d1a4 100644 --- a/app/lib/django_comments/templatetags/comments.py +++ b/app/lib/django_comments/templatetags/comments.py @@ -2,6 +2,7 @@ from django import template from django.template.loader import render_to_string from django.conf import settings from django.contrib.contenttypes.models import ContentType +from django.contrib.sites.shortcuts import get_current_site from django.utils.encoding import smart_text import django_comments @@ -76,10 +77,16 @@ class BaseCommentNode(template.Node): if not object_pk: return self.comment_model.objects.none() + # Explicit SITE_ID takes precedence over request. This is also how + # get_current_site operates. + site_id = getattr(settings, "SITE_ID", None) + if not site_id and ('request' in context): + site_id = get_current_site(context['request']).pk + qs = self.comment_model.objects.filter( content_type=ctype, object_pk=smart_text(object_pk), - site__pk=settings.SITE_ID, + site__pk=site_id, ) # The is_public and is_removed fields are implementation details of the diff --git a/app/lib/django_comments/views/comments.py b/app/lib/django_comments/views/comments.py index c441c30..40dfc60 100644 --- a/app/lib/django_comments/views/comments.py +++ b/app/lib/django_comments/views/comments.py @@ -3,13 +3,12 @@ from __future__ import absolute_import from django import http from django.apps import apps from django.conf import settings +from django.contrib.sites.shortcuts import get_current_site from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.shortcuts import render from django.template.loader import render_to_string from django.utils.html import escape -from django.views.decorators.csrf import csrf_protect -from django.views.decorators.csrf import csrf_exempt - +from django.views.decorators.csrf import csrf_protect, csrf_exempt from django.views.decorators.http import require_POST import django_comments @@ -41,7 +40,11 @@ def post_comment(request, next=None, using=None): """ # Fill out some initial data fields from an authenticated user, if present data = request.POST.copy() - if request.user.is_authenticated(): + try: + user_is_authenticated = request.user.is_authenticated() + except TypeError: # Django >= 1.11 + user_is_authenticated = request.user.is_authenticated + if user_is_authenticated: if not data.get('name', ''): data["name"] = request.user.get_full_name() or request.user.get_username() if not data.get('email', ''): @@ -102,9 +105,9 @@ def post_comment(request, next=None, using=None): ) # Otherwise create the comment - comment = form.get_comment_object() - comment.ip_address = request.META.get("REMOTE_ADDR", None) - if request.user.is_authenticated(): + comment = form.get_comment_object(site_id=get_current_site(request).id) + comment.ip_address = request.META.get("REMOTE_ADDR", None) or None + if user_is_authenticated: comment.user = request.user # Signal that the comment is about to be saved diff --git a/app/lib/django_comments/views/moderation.py b/app/lib/django_comments/views/moderation.py index 4460569..04c665f 100644 --- a/app/lib/django_comments/views/moderation.py +++ b/app/lib/django_comments/views/moderation.py @@ -1,7 +1,7 @@ from __future__ import absolute_import -from django.conf import settings from django.contrib.auth.decorators import login_required, permission_required +from django.contrib.sites.shortcuts import get_current_site from django.shortcuts import get_object_or_404, render from django.views.decorators.csrf import csrf_protect @@ -21,7 +21,9 @@ def flag(request, comment_id, next=None): comment the flagged `comments.comment` object """ - comment = get_object_or_404(django_comments.get_model(), pk=comment_id, site__pk=settings.SITE_ID) + comment = get_object_or_404(django_comments.get_model(), + pk=comment_id, + site__pk=get_current_site(request).pk) # Flag on POST if request.method == 'POST': @@ -46,7 +48,9 @@ def delete(request, comment_id, next=None): comment the flagged `comments.comment` object """ - comment = get_object_or_404(django_comments.get_model(), pk=comment_id, site__pk=settings.SITE_ID) + comment = get_object_or_404(django_comments.get_model(), + pk=comment_id, + site__pk=get_current_site(request).pk) # Delete on POST if request.method == 'POST': @@ -72,7 +76,9 @@ def approve(request, comment_id, next=None): comment the `comments.comment` object for approval """ - comment = get_object_or_404(django_comments.get_model(), pk=comment_id, site__pk=settings.SITE_ID) + comment = get_object_or_404(django_comments.get_model(), + pk=comment_id, + site__pk=get_current_site(request).pk) # Delete on POST if request.method == 'POST': diff --git a/app/lib/django_comments_old/__init__.py b/app/lib/django_comments_old/__init__.py deleted file mode 100644 index 225b195..0000000 --- a/app/lib/django_comments_old/__init__.py +++ /dev/null @@ -1,91 +0,0 @@ -from django.conf import settings -from django.core import urlresolvers -from django.core.exceptions import ImproperlyConfigured -from importlib import import_module - -DEFAULT_COMMENTS_APP = 'django_comments' - -def get_comment_app(): - """ - Get the comment app (i.e. "django_comments") as defined in the settings - """ - # Make sure the app's in INSTALLED_APPS - comments_app = get_comment_app_name() - if comments_app not in settings.INSTALLED_APPS: - raise ImproperlyConfigured("The COMMENTS_APP (%r) "\ - "must be in INSTALLED_APPS" % settings.COMMENTS_APP) - - # Try to import the package - try: - package = import_module(comments_app) - except ImportError as e: - raise ImproperlyConfigured("The COMMENTS_APP setting refers to "\ - "a non-existing package. (%s)" % e) - - return package - -def get_comment_app_name(): - """ - Returns the name of the comment app (either the setting value, if it - exists, or the default). - """ - return getattr(settings, 'COMMENTS_APP', DEFAULT_COMMENTS_APP) - -def get_model(): - from django_comments.models import Comment - """ - Returns the comment model class. - """ - if get_comment_app_name() != DEFAULT_COMMENTS_APP and hasattr(get_comment_app(), "get_model"): - return get_comment_app().get_model() - else: - return Comment - -def get_form(): - from django_comments.forms import CommentForm - """ - Returns the comment ModelForm class. - """ - if get_comment_app_name() != DEFAULT_COMMENTS_APP and hasattr(get_comment_app(), "get_form"): - return get_comment_app().get_form() - else: - return CommentForm - -def get_form_target(): - """ - Returns the target URL for the comment form submission view. - """ - if get_comment_app_name() != DEFAULT_COMMENTS_APP and hasattr(get_comment_app(), "get_form_target"): - return get_comment_app().get_form_target() - else: - return urlresolvers.reverse("django_comments.views.comments.post_comment") - -def get_flag_url(comment): - """ - Get the URL for the "flag this comment" view. - """ - if get_comment_app_name() != DEFAULT_COMMENTS_APP and hasattr(get_comment_app(), "get_flag_url"): - return get_comment_app().get_flag_url(comment) - else: - return urlresolvers.reverse("django_comments.views.moderation.flag", - args=(comment.id,)) - -def get_delete_url(comment): - """ - Get the URL for the "delete this comment" view. - """ - if get_comment_app_name() != DEFAULT_COMMENTS_APP and hasattr(get_comment_app(), "get_delete_url"): - return get_comment_app().get_delete_url(comment) - else: - return urlresolvers.reverse("django_comments.views.moderation.delete", - args=(comment.id,)) - -def get_approve_url(comment): - """ - Get the URL for the "approve this comment from moderation" view. - """ - if get_comment_app_name() != DEFAULT_COMMENTS_APP and hasattr(get_comment_app(), "get_approve_url"): - return get_comment_app().get_approve_url(comment) - else: - return urlresolvers.reverse("django_comments.views.moderation.approve", - args=(comment.id,)) diff --git a/app/lib/django_comments_old/admin.py b/app/lib/django_comments_old/admin.py deleted file mode 100644 index 8a5c063..0000000 --- a/app/lib/django_comments_old/admin.py +++ /dev/null @@ -1,87 +0,0 @@ -from __future__ import unicode_literals - -from django.contrib import admin -from django.contrib.auth import get_user_model -from django.utils.translation import ugettext_lazy as _, ungettext - -from django_comments.models import Comment -from django_comments import get_model -from django_comments.views.moderation import perform_flag, perform_approve, perform_delete - - -class UsernameSearch(object): - """The User object may not be auth.User, so we need to provide - a mechanism for issuing the equivalent of a .filter(user__username=...) - search in CommentAdmin. - """ - def __str__(self): - return 'user__%s' % get_user_model().USERNAME_FIELD - - -class CommentsAdmin(admin.ModelAdmin): - fieldsets = ( - (None, - {'fields': ('content_type', 'object_pk', 'site')} - ), - (_('Content'), - {'fields': ('user', 'user_name', 'user_email', 'user_url', 'comment')} - ), - (_('Metadata'), - {'fields': ('submit_date', 'ip_address', 'is_public', 'is_removed')} - ), - ) - - list_display = ('name', 'content_type', 'object_pk', 'ip_address', 'submit_date', 'is_public', 'is_removed') - list_filter = ('submit_date', 'site', 'is_public', 'is_removed') - date_hierarchy = 'submit_date' - ordering = ('-submit_date',) - raw_id_fields = ('user',) - search_fields = ('comment', UsernameSearch(), 'user_name', 'user_email', 'user_url', 'ip_address') - actions = ["flag_comments", "approve_comments", "remove_comments"] - - def get_actions(self, request): - actions = super(CommentsAdmin, self).get_actions(request) - # Only superusers should be able to delete the comments from the DB. - if not request.user.is_superuser and 'delete_selected' in actions: - actions.pop('delete_selected') - if not request.user.has_perm('django_comments.can_moderate'): - if 'approve_comments' in actions: - actions.pop('approve_comments') - if 'remove_comments' in actions: - actions.pop('remove_comments') - return actions - - def flag_comments(self, request, queryset): - self._bulk_flag(request, queryset, perform_flag, - lambda n: ungettext('flagged', 'flagged', n)) - flag_comments.short_description = _("Flag selected comments") - - def approve_comments(self, request, queryset): - self._bulk_flag(request, queryset, perform_approve, - lambda n: ungettext('approved', 'approved', n)) - approve_comments.short_description = _("Approve selected comments") - - def remove_comments(self, request, queryset): - self._bulk_flag(request, queryset, perform_delete, - lambda n: ungettext('removed', 'removed', n)) - remove_comments.short_description = _("Remove selected comments") - - def _bulk_flag(self, request, queryset, action, done_message): - """ - Flag, approve, or remove some comments from an admin action. Actually - calls the `action` argument to perform the heavy lifting. - """ - n_comments = 0 - for comment in queryset: - action(request, comment) - n_comments += 1 - - msg = ungettext('1 comment was successfully %(action)s.', - '%(count)s comments were successfully %(action)s.', - n_comments) - self.message_user(request, msg % {'count': n_comments, 'action': done_message(n_comments)}) - -# Only register the default admin if the model is the built-in comment model -# (this won't be true if there's a custom comment app). -if get_model() is Comment: - admin.site.register(Comment, CommentsAdmin) diff --git a/app/lib/django_comments_old/akismet.py b/app/lib/django_comments_old/akismet.py deleted file mode 100644 index daa4281..0000000 --- a/app/lib/django_comments_old/akismet.py +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/python - -__version__ = "0.3" -__date__ = "2005-12-01" -__author__ = "David Lynch (kemayo AT Google's mail service DOT com)" -__copyright__ = "Copyright 2005, David Lynch" -__license__ = "New BSD" -__history__ = """ -0.3 - 20051205 - Cleaned up __post. -0.2 - 20051201 - Added documentation, and tweaked the circumstances where an error - will be thrown. -0.1 - 20051201 - Initial release. Everything pretty much works. Probably. -""" - -import http.client -from urllib.parse import urlencode - -USERAGENT = "" -AKISMET_URL = "rest.akismet.com" -AKISMET_PORT = 80 - - -class AkismetError(Exception): - def __init__(self, response, statuscode): - self.response = response - self.statuscode = statuscode - - def __str__(self): - return repr(self.value) - - -def __post(request, host, path, port=80): - connection = http.client.HTTPConnection(host, port) - connection.request("POST", path, request, { - "User-Agent": "%s | %s/%s" % (USERAGENT, "Akistmet.py", __version__), - "Content-type": "application/x-www-form-urlencoded" - }) - response = connection.getresponse() - return response.read(), response.status - - -def verify_key(key, blog): - """Find out whether a given WordPress.com API key is valid. - Required parameters: - key: A WordPress.com API key. - blog: URL of the front page of the site comments will be submitted to. - Returns True if a valid key, False if invalid. - """ - response, status = __post("key=%s&blog=%s" % (key, blog), AKISMET_URL, "/1.1/verify-key", AKISMET_PORT) - if response == "valid": - return True - elif response == "invalid": - return False - else: - raise AkismetError(response, status) - - -def comment_check(key, blog, user_ip, user_agent, **other): - """Submit a comment to find out whether Akismet thinks that it's spam. - Required parameters: - key: A valid WordPress.com API key, as tested with verify_key(). - blog: URL of the front page of the site the comment will appear on. - user_ip: IP address of the being which submitted the comment. - user_agent: User agent reported by said being. - Suggested "other" keys: "permalink", "referrer", "comment_type", "comment_author", - "comment_author_email", "comment_author_url", "comment_content", and any other HTTP - headers sent from the client. - More detail on what should be submitted is available at: - http://akismet.com/development/api/ - Returns True if spam, False if ham. Throws an AkismetError if the server says - anything unexpected. - """ - request = {'blog': blog, 'user_ip': user_ip, 'user_agent': user_agent} - request.update(other) - response, status = __post(urlencode(request), "%s.%s" % (key, AKISMET_URL), "/1.1/comment-check", AKISMET_PORT) - if response == "true": - return True - elif response == "false": - return False - else: - raise AkismetError(response, status) - - -def submit_spam(key, blog, user_ip, user_agent, **other): - """Report a false negative to Akismet. - Same arguments as comment_check. - Doesn't return anything. Throws an AkismetError if the server says anything. - """ - request = {'blog': blog, 'user_ip': user_ip, 'user_agent': user_agent} - request.update(other) - response, status = __post(urlencode(request), "%s.%s" % (key, AKISMET_URL), "/1.1/submit-spam", AKISMET_PORT) - if status != 200 or response != "": - raise AkismetError(response, status) - - -def submit_ham(key, blog, user_ip, user_agent, **other): - """Report a false positive to Akismet. - Same arguments as comment_check. - Doesn't return anything. Throws an AkismetError if the server says anything. - """ - request = {'blog': blog, 'user_ip': user_ip, 'user_agent': user_agent} - request.update(other) - response, status = __post(urlencode(request), "%s.%s" % (key, AKISMET_URL), "/1.1/submit-ham", AKISMET_PORT) - if status != 200 or response != "": - raise AkismetError(response, status) diff --git a/app/lib/django_comments_old/feeds.py b/app/lib/django_comments_old/feeds.py deleted file mode 100644 index 0b8ce5b..0000000 --- a/app/lib/django_comments_old/feeds.py +++ /dev/null @@ -1,32 +0,0 @@ -from django.contrib.syndication.views import Feed -from django.contrib.sites.models import get_current_site -from django.utils.translation import ugettext as _ - -import django_comments - -class LatestCommentFeed(Feed): - """Feed of latest comments on the current site.""" - - def __call__(self, request, *args, **kwargs): - self.site = get_current_site(request) - return super(LatestCommentFeed, self).__call__(request, *args, **kwargs) - - def title(self): - return _("%(site_name)s comments") % dict(site_name=self.site.name) - - def link(self): - return "http://%s/" % (self.site.domain) - - def description(self): - return _("Latest comments on %(site_name)s") % dict(site_name=self.site.name) - - def items(self): - qs = django_comments.get_model().objects.filter( - site__pk = self.site.pk, - is_public = True, - is_removed = False, - ) - return qs.order_by('-submit_date')[:40] - - def item_pubdate(self, item): - return item.submit_date diff --git a/app/lib/django_comments_old/forms.py b/app/lib/django_comments_old/forms.py deleted file mode 100644 index b9249c0..0000000 --- a/app/lib/django_comments_old/forms.py +++ /dev/null @@ -1,197 +0,0 @@ -import time -from django import forms -from django.forms.utils import ErrorDict -from django.conf import settings -from django.contrib.contenttypes.models import ContentType -from django.utils.crypto import salted_hmac, constant_time_compare -from django.utils.encoding import force_text -from django.utils.text import get_text_list -from django.utils import timezone -from django.utils.translation import ungettext, ugettext, ugettext_lazy as _ - -from django_comments.models import Comment - -COMMENT_MAX_LENGTH = getattr(settings,'COMMENT_MAX_LENGTH', 3000) - -class CommentSecurityForm(forms.Form): - """ - Handles the security aspects (anti-spoofing) for comment forms. - """ - content_type = forms.CharField(widget=forms.HiddenInput) - object_pk = forms.CharField(widget=forms.HiddenInput) - timestamp = forms.IntegerField(widget=forms.HiddenInput) - security_hash = forms.CharField(min_length=40, max_length=40, widget=forms.HiddenInput) - - def __init__(self, target_object, data=None, initial=None): - self.target_object = target_object - if initial is None: - initial = {} - initial.update(self.generate_security_data()) - super(CommentSecurityForm, self).__init__(data=data, initial=initial) - - def security_errors(self): - """Return just those errors associated with security""" - errors = ErrorDict() - for f in ["honeypot", "timestamp", "security_hash"]: - if f in self.errors: - errors[f] = self.errors[f] - return errors - - def clean_security_hash(self): - """Check the security hash.""" - security_hash_dict = { - 'content_type' : self.data.get("content_type", ""), - 'object_pk' : self.data.get("object_pk", ""), - 'timestamp' : self.data.get("timestamp", ""), - } - expected_hash = self.generate_security_hash(**security_hash_dict) - actual_hash = self.cleaned_data["security_hash"] - if not constant_time_compare(expected_hash, actual_hash): - raise forms.ValidationError("Security hash check failed.") - return actual_hash - - def clean_timestamp(self): - """Make sure the timestamp isn't too far (> 2 hours) in the past.""" - ts = self.cleaned_data["timestamp"] - """ - if time.time() - ts > (2 * 60 * 60): - raise forms.ValidationError("Timestamp check failed") - """ - return ts - - def generate_security_data(self): - """Generate a dict of security data for "initial" data.""" - timestamp = int(time.time()) - security_dict = { - 'content_type' : str(self.target_object._meta), - 'object_pk' : str(self.target_object._get_pk_val()), - 'timestamp' : str(timestamp), - 'security_hash' : self.initial_security_hash(timestamp), - } - return security_dict - - def initial_security_hash(self, timestamp): - """ - Generate the initial security hash from self.content_object - and a (unix) timestamp. - """ - - initial_security_dict = { - 'content_type' : str(self.target_object._meta), - 'object_pk' : str(self.target_object._get_pk_val()), - 'timestamp' : str(timestamp), - } - return self.generate_security_hash(**initial_security_dict) - - def generate_security_hash(self, content_type, object_pk, timestamp): - """ - Generate a HMAC security hash from the provided info. - """ - info = (content_type, object_pk, timestamp) - key_salt = "django.contrib.forms.CommentSecurityForm" - value = "-".join(info) - return salted_hmac(key_salt, value).hexdigest() - -class CommentDetailsForm(CommentSecurityForm): - """ - Handles the specific details of the comment (name, comment, etc.). - """ - name = forms.CharField(label=_("Name"), max_length=50) - email = forms.EmailField(label=_("Email address")) - url = forms.URLField(label=_("URL"), required=False) - comment = forms.CharField(label=_('Comment'), widget=forms.Textarea, - max_length=COMMENT_MAX_LENGTH) - - def get_comment_object(self): - """ - Return a new (unsaved) comment object based on the information in this - form. Assumes that the form is already validated and will throw a - ValueError if not. - - Does not set any of the fields that would come from a Request object - (i.e. ``user`` or ``ip_address``). - """ - if not self.is_valid(): - raise ValueError("get_comment_object may only be called on valid forms") - - CommentModel = self.get_comment_model() - new = CommentModel(**self.get_comment_create_data()) - new = self.check_for_duplicate_comment(new) - - return new - - def get_comment_model(self): - """ - Get the comment model to create with this form. Subclasses in custom - comment apps should override this, get_comment_create_data, and perhaps - check_for_duplicate_comment to provide custom comment models. - """ - return Comment - - def get_comment_create_data(self): - """ - Returns the dict of data to be used to create a comment. Subclasses in - custom comment apps that override get_comment_model can override this - method to add extra fields onto a custom comment model. - """ - return dict( - content_type = ContentType.objects.get_for_model(self.target_object), - object_pk = force_text(self.target_object._get_pk_val()), - user_name = self.cleaned_data["name"], - user_email = self.cleaned_data["email"], - user_url = self.cleaned_data["url"], - comment = self.cleaned_data["comment"], - submit_date = timezone.now(), - site_id = settings.SITE_ID, - is_public = True, - is_removed = False, - ) - - def check_for_duplicate_comment(self, new): - """ - Check that a submitted comment isn't a duplicate. This might be caused - by someone posting a comment twice. If it is a dup, silently return the *previous* comment. - """ - possible_duplicates = self.get_comment_model()._default_manager.using( - self.target_object._state.db - ).filter( - content_type = new.content_type, - object_pk = new.object_pk, - user_name = new.user_name, - user_email = new.user_email, - user_url = new.user_url, - ) - for old in possible_duplicates: - if old.submit_date.date() == new.submit_date.date() and old.comment == new.comment: - return old - - return new - - def clean_comment(self): - """ - If COMMENTS_ALLOW_PROFANITIES is False, check that the comment doesn't - contain anything in PROFANITIES_LIST. - """ - comment = self.cleaned_data["comment"] - if settings.COMMENTS_ALLOW_PROFANITIES == False: - bad_words = [w for w in settings.PROFANITIES_LIST if w in comment.lower()] - if bad_words: - raise forms.ValidationError(ungettext( - "Watch your mouth! The word %s is not allowed here.", - "Watch your mouth! The words %s are not allowed here.", - len(bad_words)) % get_text_list( - ['"%s%s%s"' % (i[0], '-'*(len(i)-2), i[-1]) - for i in bad_words], ugettext('and'))) - return comment - -class CommentForm(CommentDetailsForm): - honeypot = forms.CharField(required=False, - label=_('If you enter anything in this field '\ - 'your comment will be treated as spam')) - - def clean_honeypot(self): - """Check that nothing's been entered into the honeypot.""" - value = self.cleaned_data["honeypot"] - if value: - raise forms.ValidationError(self.fields["honeypot"].label) - return value diff --git a/app/lib/django_comments_old/managers.py b/app/lib/django_comments_old/managers.py deleted file mode 100644 index bc0fc5f..0000000 --- a/app/lib/django_comments_old/managers.py +++ /dev/null @@ -1,22 +0,0 @@ -from django.db import models -from django.contrib.contenttypes.models import ContentType -from django.utils.encoding import force_text - -class CommentManager(models.Manager): - - def in_moderation(self): - """ - QuerySet for all comments currently in the moderation queue. - """ - return self.get_query_set().filter(is_public=False, is_removed=False) - - def for_model(self, model): - """ - QuerySet for all comments for a particular model (either an instance or - a class). - """ - ct = ContentType.objects.get_for_model(model) - qs = self.get_query_set().filter(content_type=ct) - if isinstance(model, models.Model): - qs = qs.filter(object_pk=force_text(model._get_pk_val())) - return qs diff --git a/app/lib/django_comments_old/models.py b/app/lib/django_comments_old/models.py deleted file mode 100644 index 6ba1f30..0000000 --- a/app/lib/django_comments_old/models.py +++ /dev/null @@ -1,204 +0,0 @@ -from django.conf import settings -try: - from django.contrib.contenttypes.fields import GenericForeignKey -except ImportError: - from django.contrib.contenttypes.generic import GenericForeignKey -from django.contrib.contenttypes.models import ContentType -from django.contrib.sites.models import Site -from django.core import urlresolvers -from django.db import models -from django.utils.translation import ugettext_lazy as _ -from django.utils import timezone -from django.utils.encoding import python_2_unicode_compatible - -from django_comments.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") - 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) - - class Meta: - abstract = True - - def get_content_object_url(self): - """ - Get a URL suitable for redirecting to the content object. - """ - return urlresolvers.reverse( - "comments-url-redirect", - args=(self.content_type_id, self.object_pk) - ) - - -@python_2_unicode_compatible -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(settings.AUTH_USER_MODEL, 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.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: - db_table = "django_comments" - 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(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"): - 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 - - -@python_2_unicode_compatible -class CommentFlag(models.Model): - """ - Records a flag on a comment. This is intentionally flexible; right now, a - flag could be: - - * A "removal suggestion" -- where a user suggests a comment for (potential) removal. - - * A "moderator deletion" -- used when a moderator deletes a comment. - - You can (ab)use this model to add other flags, if needed. However, by - design users are only allowed to flag a comment with a given flag once; - if you want rating look elsewhere. - """ - user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_('user'), related_name="comment_flags") - comment = models.ForeignKey(Comment, verbose_name=_('comment'), related_name="flags") - flag = models.CharField(_('flag'), max_length=30, db_index=True) - flag_date = models.DateTimeField(_('date'), default=None) - - # Constants for flag types - SUGGEST_REMOVAL = "removal suggestion" - MODERATOR_DELETION = "moderator deletion" - MODERATOR_APPROVAL = "moderator approval" - - class Meta: - db_table = 'django_comment_flags' - unique_together = [('user', 'comment', 'flag')] - verbose_name = _('comment flag') - verbose_name_plural = _('comment flags') - - def __str__(self): - return "%s flag of comment ID %s by %s" % \ - (self.flag, self.comment_id, self.user.get_username()) - - def save(self, *args, **kwargs): - if self.flag_date is None: - self.flag_date = timezone.now() - super(CommentFlag, self).save(*args, **kwargs) diff --git a/app/lib/django_comments_old/moderation.py b/app/lib/django_comments_old/moderation.py deleted file mode 100644 index ebb29da..0000000 --- a/app/lib/django_comments_old/moderation.py +++ /dev/null @@ -1,357 +0,0 @@ -""" -A generic comment-moderation system which allows configuration of -moderation options on a per-model basis. - -To use, do two things: - -1. Create or import a subclass of ``CommentModerator`` defining the - options you want. - -2. Import ``moderator`` from this module and register one or more - models, passing the models and the ``CommentModerator`` options - class you want to use. - - -Example -------- - -First, we define a simple model class which might represent entries in -a Weblog:: - - from django.db import models - - class Entry(models.Model): - title = models.CharField(maxlength=250) - body = models.TextField() - pub_date = models.DateField() - enable_comments = models.BooleanField() - -Then we create a ``CommentModerator`` subclass specifying some -moderation options:: - - from django_comments.moderation import CommentModerator, moderator - - class EntryModerator(CommentModerator): - email_notification = True - enable_field = 'enable_comments' - -And finally register it for moderation:: - - moderator.register(Entry, EntryModerator) - -This sample class would apply two moderation steps to each new -comment submitted on an Entry: - -* If the entry's ``enable_comments`` field is set to ``False``, the - comment will be rejected (immediately deleted). - -* If the comment is successfully posted, an email notification of the - comment will be sent to site staff. - -For a full list of built-in moderation options and other -configurability, see the documentation for the ``CommentModerator`` -class. - -""" - -import datetime - -from django.conf import settings -from django.core.mail import send_mail -from django.db.models.base import ModelBase -from django.template import Context, loader -from django.contrib.sites.shortcuts import get_current_site -from django.utils import timezone - -import django_comments -from django_comments import signals - -class AlreadyModerated(Exception): - """ - Raised when a model which is already registered for moderation is - attempting to be registered again. - - """ - pass - -class NotModerated(Exception): - """ - Raised when a model which is not registered for moderation is - attempting to be unregistered. - - """ - pass - -class CommentModerator(object): - """ - Encapsulates comment-moderation options for a given model. - - This class is not designed to be used directly, since it doesn't - enable any of the available moderation options. Instead, subclass - it and override attributes to enable different options:: - - ``auto_close_field`` - If this is set to the name of a ``DateField`` or - ``DateTimeField`` on the model for which comments are - being moderated, new comments for objects of that model - will be disallowed (immediately deleted) when a certain - number of days have passed after the date specified in - that field. Must be used in conjunction with - ``close_after``, which specifies the number of days past - which comments should be disallowed. Default value is - ``None``. - - ``auto_moderate_field`` - Like ``auto_close_field``, but instead of outright - deleting new comments when the requisite number of days - have elapsed, it will simply set the ``is_public`` field - of new comments to ``False`` before saving them. Must be - used in conjunction with ``moderate_after``, which - specifies the number of days past which comments should be - moderated. Default value is ``None``. - - ``close_after`` - If ``auto_close_field`` is used, this must specify the - number of days past the value of the field specified by - ``auto_close_field`` after which new comments for an - object should be disallowed. Default value is ``None``. - - ``email_notification`` - If ``True``, any new comment on an object of this model - which survives moderation will generate an email to site - staff. Default value is ``False``. - - ``enable_field`` - If this is set to the name of a ``BooleanField`` on the - model for which comments are being moderated, new comments - on objects of that model will be disallowed (immediately - deleted) whenever the value of that field is ``False`` on - the object the comment would be attached to. Default value - is ``None``. - - ``moderate_after`` - If ``auto_moderate_field`` is used, this must specify the number - of days past the value of the field specified by - ``auto_moderate_field`` after which new comments for an - object should be marked non-public. Default value is - ``None``. - - Most common moderation needs can be covered by changing these - attributes, but further customization can be obtained by - subclassing and overriding the following methods. Each method will - be called with three arguments: ``comment``, which is the comment - being submitted, ``content_object``, which is the object the - comment will be attached to, and ``request``, which is the - ``HttpRequest`` in which the comment is being submitted:: - - ``allow`` - Should return ``True`` if the comment should be allowed to - post on the content object, and ``False`` otherwise (in - which case the comment will be immediately deleted). - - ``email`` - If email notification of the new comment should be sent to - site staff or moderators, this method is responsible for - sending the email. - - ``moderate`` - Should return ``True`` if the comment should be moderated - (in which case its ``is_public`` field will be set to - ``False`` before saving), and ``False`` otherwise (in - which case the ``is_public`` field will not be changed). - - Subclasses which want to introspect the model for which comments - are being moderated can do so through the attribute ``_model``, - which will be the model class. - - """ - auto_close_field = None - auto_moderate_field = None - close_after = None - email_notification = False - enable_field = None - moderate_after = None - - def __init__(self, model): - self._model = model - - def _get_delta(self, now, then): - """ - Internal helper which will return a ``datetime.timedelta`` - representing the time between ``now`` and ``then``. Assumes - ``now`` is a ``datetime.date`` or ``datetime.datetime`` later - than ``then``. - - If ``now`` and ``then`` are not of the same type due to one of - them being a ``datetime.date`` and the other being a - ``datetime.datetime``, both will be coerced to - ``datetime.date`` before calculating the delta. - - """ - if now.__class__ is not then.__class__: - now = datetime.date(now.year, now.month, now.day) - then = datetime.date(then.year, then.month, then.day) - if now < then: - raise ValueError("Cannot determine moderation rules because date field is set to a value in the future") - return now - then - - def allow(self, comment, content_object, request): - """ - Determine whether a given comment is allowed to be posted on - a given object. - - Return ``True`` if the comment should be allowed, ``False - otherwise. - - """ - if self.enable_field: - if not getattr(content_object, self.enable_field): - return False - if self.auto_close_field and self.close_after is not None: - close_after_date = getattr(content_object, self.auto_close_field) - if close_after_date is not None and self._get_delta(timezone.now(), close_after_date).days >= self.close_after: - return False - return True - - def moderate(self, comment, content_object, request): - """ - Determine whether a given comment on a given object should be - allowed to show up immediately, or should be marked non-public - and await approval. - - Return ``True`` if the comment should be moderated (marked - non-public), ``False`` otherwise. - - """ - if self.auto_moderate_field and self.moderate_after is not None: - moderate_after_date = getattr(content_object, self.auto_moderate_field) - if moderate_after_date is not None and self._get_delta(timezone.now(), moderate_after_date).days >= self.moderate_after: - return True - return False - - def email(self, comment, content_object, request): - """ - Send email notification of a new comment to site staff when email - notifications have been requested. - - """ - if not self.email_notification: - return - recipient_list = [manager_tuple[1] for manager_tuple in settings.MANAGERS] - t = loader.get_template('comments/comment_notification_email.txt') - c = Context({ 'comment': comment, - 'content_object': content_object }) - subject = '[%s] New comment posted on "%s"' % (get_current_site(request).name, - content_object) - message = t.render(c) - send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, recipient_list, fail_silently=True) - -class Moderator(object): - """ - Handles moderation of a set of models. - - An instance of this class will maintain a list of one or more - models registered for comment moderation, and their associated - moderation classes, and apply moderation to all incoming comments. - - To register a model, obtain an instance of ``Moderator`` (this - module exports one as ``moderator``), and call its ``register`` - method, passing the model class and a moderation class (which - should be a subclass of ``CommentModerator``). Note that both of - these should be the actual classes, not instances of the classes. - - To cease moderation for a model, call the ``unregister`` method, - passing the model class. - - For convenience, both ``register`` and ``unregister`` can also - accept a list of model classes in place of a single model; this - allows easier registration of multiple models with the same - ``CommentModerator`` class. - - The actual moderation is applied in two phases: one prior to - saving a new comment, and the other immediately after saving. The - pre-save moderation may mark a comment as non-public or mark it to - be removed; the post-save moderation may delete a comment which - was disallowed (there is currently no way to prevent the comment - being saved once before removal) and, if the comment is still - around, will send any notification emails the comment generated. - - """ - def __init__(self): - self._registry = {} - self.connect() - - def connect(self): - """ - Hook up the moderation methods to pre- and post-save signals - from the comment models. - - """ - signals.comment_will_be_posted.connect(self.pre_save_moderation, sender=django_comments.get_model()) - signals.comment_was_posted.connect(self.post_save_moderation, sender=django_comments.get_model()) - - def register(self, model_or_iterable, moderation_class): - """ - Register a model or a list of models for comment moderation, - using a particular moderation class. - - Raise ``AlreadyModerated`` if any of the models are already - registered. - - """ - if isinstance(model_or_iterable, ModelBase): - model_or_iterable = [model_or_iterable] - for model in model_or_iterable: - if model in self._registry: - raise AlreadyModerated("The model '%s' is already being moderated" % model._meta.module_name) - self._registry[model] = moderation_class(model) - - def unregister(self, model_or_iterable): - """ - Remove a model or a list of models from the list of models - whose comments will be moderated. - - Raise ``NotModerated`` if any of the models are not currently - registered for moderation. - - """ - if isinstance(model_or_iterable, ModelBase): - model_or_iterable = [model_or_iterable] - for model in model_or_iterable: - if model not in self._registry: - raise NotModerated("The model '%s' is not currently being moderated" % model._meta.module_name) - del self._registry[model] - - def pre_save_moderation(self, sender, comment, request, **kwargs): - """ - Apply any necessary pre-save moderation steps to new - comments. - - """ - model = comment.content_type.model_class() - if model not in self._registry: - return - content_object = comment.content_object - moderation_class = self._registry[model] - - # Comment will be disallowed outright (HTTP 403 response) - if not moderation_class.allow(comment, content_object, request): - return False - - if moderation_class.moderate(comment, content_object, request): - comment.is_public = False - - def post_save_moderation(self, sender, comment, request, **kwargs): - """ - Apply any necessary post-save moderation steps to new - comments. - - """ - model = comment.content_type.model_class() - if model not in self._registry: - return - self._registry[model].email(comment, comment.content_object, request) - -# Import this instance in your own code to use in registering -# your models for moderation. -moderator = Moderator() diff --git a/app/lib/django_comments_old/signals.py b/app/lib/django_comments_old/signals.py deleted file mode 100644 index 079afaf..0000000 --- a/app/lib/django_comments_old/signals.py +++ /dev/null @@ -1,21 +0,0 @@ -""" -Signals relating to comments. -""" -from django.dispatch import Signal - -# Sent just before a comment will be posted (after it's been approved and -# moderated; this can be used to modify the comment (in place) with posting -# details or other such actions. If any receiver returns False the comment will be -# discarded and a 400 response. This signal is sent at more or less -# the same time (just before, actually) as the Comment object's pre-save signal, -# except that the HTTP request is sent along with this signal. -comment_will_be_posted = Signal(providing_args=["comment", "request"]) - -# Sent just after a comment was posted. See above for how this differs -# from the Comment object's post-save signal. -comment_was_posted = Signal(providing_args=["comment", "request"]) - -# Sent after a comment was "flagged" in some way. Check the flag to see if this -# was a user requesting removal of a comment, a moderator approving/removing a -# comment, or some other custom user flag. -comment_was_flagged = Signal(providing_args=["comment", "flag", "created", "request"]) diff --git a/app/lib/django_comments_old/templatetags/__init__.py b/app/lib/django_comments_old/templatetags/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/app/lib/django_comments_old/templatetags/__init__.py +++ /dev/null diff --git a/app/lib/django_comments_old/templatetags/comments.py b/app/lib/django_comments_old/templatetags/comments.py deleted file mode 100644 index 5ff156b..0000000 --- a/app/lib/django_comments_old/templatetags/comments.py +++ /dev/null @@ -1,334 +0,0 @@ -from django import template -from django.template.loader import render_to_string -from django.conf import settings -from django.contrib.contenttypes.models import ContentType -from django.utils.encoding import smart_text - -import django_comments - -register = template.Library() - - -class BaseCommentNode(template.Node): - """ - Base helper class (abstract) for handling the get_comment_* template tags. - Looks a bit strange, but the subclasses below should make this a bit more - obvious. - """ - - @classmethod - def handle_token(cls, parser, token): - """Class method to parse get_comment_list/count/form and return a Node.""" - tokens = token.split_contents() - if tokens[1] != 'for': - raise template.TemplateSyntaxError("Second argument in %r tag must be 'for'" % tokens[0]) - - # {% get_whatever for obj as varname %} - if len(tokens) == 5: - if tokens[3] != 'as': - raise template.TemplateSyntaxError("Third argument in %r must be 'as'" % tokens[0]) - return cls( - object_expr = parser.compile_filter(tokens[2]), - as_varname = tokens[4], - ) - - # {% get_whatever for app.model pk as varname %} - elif len(tokens) == 6: - if tokens[4] != 'as': - raise template.TemplateSyntaxError("Fourth argument in %r must be 'as'" % tokens[0]) - return cls( - ctype = BaseCommentNode.lookup_content_type(tokens[2], tokens[0]), - object_pk_expr = parser.compile_filter(tokens[3]), - as_varname = tokens[5] - ) - - else: - raise template.TemplateSyntaxError("%r tag requires 4 or 5 arguments" % tokens[0]) - - @staticmethod - def lookup_content_type(token, tagname): - try: - app, model = token.split('.') - return ContentType.objects.get_by_natural_key(app, model) - except ValueError: - raise template.TemplateSyntaxError("Third argument in %r must be in the format 'app.model'" % tagname) - except ContentType.DoesNotExist: - raise template.TemplateSyntaxError("%r tag has non-existant content-type: '%s.%s'" % (tagname, app, model)) - - def __init__(self, ctype=None, object_pk_expr=None, object_expr=None, as_varname=None, comment=None): - if ctype is None and object_expr is None: - raise template.TemplateSyntaxError("Comment nodes must be given either a literal object or a ctype and object pk.") - self.comment_model = django_comments.get_model() - self.as_varname = as_varname - self.ctype = ctype - self.object_pk_expr = object_pk_expr - self.object_expr = object_expr - self.comment = comment - - def render(self, context): - qs = self.get_query_set(context) - context[self.as_varname] = self.get_context_value_from_queryset(context, qs) - return '' - - def get_query_set(self, context): - ctype, object_pk = self.get_target_ctype_pk(context) - if not object_pk: - return self.comment_model.objects.none() - - qs = self.comment_model.objects.filter( - content_type = ctype, - object_pk = smart_text(object_pk), - site__pk = settings.SITE_ID, - ) - - # The is_public and is_removed fields are implementation details of the - # built-in comment model's spam filtering system, so they might not - # be present on a custom comment model subclass. If they exist, we - # should filter on them. - field_names = [f.name for f in self.comment_model._meta.fields] - if 'is_public' in field_names: - qs = qs.filter(is_public=True) - if getattr(settings, 'COMMENTS_HIDE_REMOVED', True) and 'is_removed' in field_names: - qs = qs.filter(is_removed=False) - - return qs - - def get_target_ctype_pk(self, context): - if self.object_expr: - try: - obj = self.object_expr.resolve(context) - except template.VariableDoesNotExist: - return None, None - return ContentType.objects.get_for_model(obj), obj.pk - else: - return self.ctype, self.object_pk_expr.resolve(context, ignore_failures=True) - - def get_context_value_from_queryset(self, context, qs): - """Subclasses should override this.""" - raise NotImplementedError - -class CommentListNode(BaseCommentNode): - """Insert a list of comments into the context.""" - def get_context_value_from_queryset(self, context, qs): - return list(qs) - -class CommentCountNode(BaseCommentNode): - """Insert a count of comments into the context.""" - def get_context_value_from_queryset(self, context, qs): - return qs.count() - -class CommentFormNode(BaseCommentNode): - """Insert a form for the comment model into the context.""" - - def get_form(self, context): - obj = self.get_object(context) - if obj: - return django_comments.get_form()(obj) - else: - return None - - def get_object(self, context): - if self.object_expr: - try: - return self.object_expr.resolve(context) - except template.VariableDoesNotExist: - return None - else: - object_pk = self.object_pk_expr.resolve(context, - ignore_failures=True) - return self.ctype.get_object_for_this_type(pk=object_pk) - - def render(self, context): - context[self.as_varname] = self.get_form(context) - return '' - -class RenderCommentFormNode(CommentFormNode): - """Render the comment form directly""" - - @classmethod - def handle_token(cls, parser, token): - """Class method to parse render_comment_form and return a Node.""" - tokens = token.split_contents() - if tokens[1] != 'for': - raise template.TemplateSyntaxError("Second argument in %r tag must be 'for'" % tokens[0]) - - # {% render_comment_form for obj %} - if len(tokens) == 3: - return cls(object_expr=parser.compile_filter(tokens[2])) - - # {% render_comment_form for app.models pk %} - elif len(tokens) == 4: - return cls( - ctype = BaseCommentNode.lookup_content_type(tokens[2], tokens[0]), - object_pk_expr = parser.compile_filter(tokens[3]) - ) - - def render(self, context): - ctype, object_pk = self.get_target_ctype_pk(context) - if object_pk: - template_search_list = [ - "comments/%s/%s/form.html" % (ctype.app_label, ctype.model), - "comments/%s/form.html" % ctype.app_label, - "comments/form.html" - ] - context.push() - formstr = render_to_string(template_search_list, {"form" : self.get_form(context)}, context) - context.pop() - return formstr - else: - return '' - -class RenderCommentListNode(CommentListNode): - """Render the comment list directly""" - - @classmethod - def handle_token(cls, parser, token): - """Class method to parse render_comment_list and return a Node.""" - tokens = token.split_contents() - if tokens[1] != 'for': - raise template.TemplateSyntaxError("Second argument in %r tag must be 'for'" % tokens[0]) - - # {% render_comment_list for obj %} - if len(tokens) == 3: - return cls(object_expr=parser.compile_filter(tokens[2])) - - # {% render_comment_list for app.models pk %} - elif len(tokens) == 4: - return cls( - ctype = BaseCommentNode.lookup_content_type(tokens[2], tokens[0]), - object_pk_expr = parser.compile_filter(tokens[3]) - ) - - def render(self, context): - ctype, object_pk = self.get_target_ctype_pk(context) - if object_pk: - template_search_list = [ - "comments/%s/%s/list.html" % (ctype.app_label, ctype.model), - "comments/%s/list.html" % ctype.app_label, - "comments/list.html" - ] - qs = self.get_query_set(context) - context.push() - liststr = render_to_string(template_search_list, { - "comment_list" : self.get_context_value_from_queryset(context, qs) - }, context) - context.pop() - return liststr - else: - return '' - -# We could just register each classmethod directly, but then we'd lose out on -# the automagic docstrings-into-admin-docs tricks. So each node gets a cute -# wrapper function that just exists to hold the docstring. - -@register.tag -def get_comment_count(parser, token): - """ - Gets the comment count for the given params and populates the template - context with a variable containing that value, whose name is defined by the - 'as' clause. - - Syntax:: - - {% get_comment_count for [object] as [varname] %} - {% get_comment_count for [app].[model] [object_id] as [varname] %} - - Example usage:: - - {% get_comment_count for event as comment_count %} - {% get_comment_count for calendar.event event.id as comment_count %} - {% get_comment_count for calendar.event 17 as comment_count %} - - """ - return CommentCountNode.handle_token(parser, token) - -@register.tag -def get_comment_list(parser, token): - """ - Gets the list of comments for the given params and populates the template - context with a variable containing that value, whose name is defined by the - 'as' clause. - - Syntax:: - - {% get_comment_list for [object] as [varname] %} - {% get_comment_list for [app].[model] [object_id] as [varname] %} - - Example usage:: - - {% get_comment_list for event as comment_list %} - {% for comment in comment_list %} - ... - {% endfor %} - - """ - return CommentListNode.handle_token(parser, token) - -@register.tag -def render_comment_list(parser, token): - """ - Render the comment list (as returned by ``{% get_comment_list %}``) - through the ``comments/list.html`` template - - Syntax:: - - {% render_comment_list for [object] %} - {% render_comment_list for [app].[model] [object_id] %} - - Example usage:: - - {% render_comment_list for event %} - - """ - return RenderCommentListNode.handle_token(parser, token) - -@register.tag -def get_comment_form(parser, token): - """ - Get a (new) form object to post a new comment. - - Syntax:: - - {% get_comment_form for [object] as [varname] %} - {% get_comment_form for [app].[model] [object_id] as [varname] %} - """ - return CommentFormNode.handle_token(parser, token) - -@register.tag -def render_comment_form(parser, token): - """ - Render the comment form (as returned by ``{% render_comment_form %}``) through - the ``comments/form.html`` template. - - Syntax:: - - {% render_comment_form for [object] %} - {% render_comment_form for [app].[model] [object_id] %} - """ - return RenderCommentFormNode.handle_token(parser, token) - -@register.simple_tag -def comment_form_target(): - """ - Get the target URL for the comment form. - - Example:: - - <form action="{% comment_form_target %}" method="post"> - """ - return django_comments.get_form_target() - -@register.simple_tag -def get_comment_permalink(comment, anchor_pattern=None): - """ - Get the permalink for a comment, optionally specifying the format of the - named anchor to be appended to the end of the URL. - - Example:: - {% get_comment_permalink comment "#c%(id)s-by-%(user_name)s" %} - """ - - if anchor_pattern: - return comment.get_absolute_url(anchor_pattern) - return comment.get_absolute_url() - diff --git a/app/lib/django_comments_old/urls.py b/app/lib/django_comments_old/urls.py deleted file mode 100644 index fb8f972..0000000 --- a/app/lib/django_comments_old/urls.py +++ /dev/null @@ -1,18 +0,0 @@ -from django.conf.urls import url -from .views import comments, moderation -from django.contrib.contenttypes.views import shortcut - -urlpatterns = [ - url(r'^post/$', comments.post_comment, name='comments-post-comment'), - url(r'^posted/$', comments.comment_done, name='comments-comment-done'), - url(r'^flag/(\d+)/$', moderation.flag, name='comments-flag'), - url(r'^flagged/$', moderation.flag_done, name='comments-flag-done'), - url(r'^delete/(\d+)/$', moderation.delete, name='comments-delete'), - url(r'^deleted/$', moderation.delete_done, name='comments-delete-done'), - url(r'^approve/(\d+)/$', moderation.approve, name='comments-approve'), - url(r'^approved/$', moderation.approve_done, name='comments-approve-done'), -] - -urlpatterns += [ - url(r'^cr/(\d+)/(.+)/$', shortcut, name='comments-url-redirect'), -] diff --git a/app/lib/django_comments_old/views/__init__.py b/app/lib/django_comments_old/views/__init__.py deleted file mode 100644 index e69de29..0000000 --- a/app/lib/django_comments_old/views/__init__.py +++ /dev/null diff --git a/app/lib/django_comments_old/views/comments.py b/app/lib/django_comments_old/views/comments.py deleted file mode 100644 index b44babf..0000000 --- a/app/lib/django_comments_old/views/comments.py +++ /dev/null @@ -1,140 +0,0 @@ -from __future__ import absolute_import - -from django import http -from django.conf import settings -from django.core.exceptions import ObjectDoesNotExist, ValidationError -from django.db import models -from django.shortcuts import render_to_response -from django.template import RequestContext -from django.template.loader import render_to_string -from django.utils.html import escape -from django.views.decorators.csrf import csrf_protect -from django.views.decorators.http import require_POST -try: - from django.apps import apps -except ImportError: - from django.db import models as apps - -import django_comments -from django_comments import signals -from django_comments.views.utils import next_redirect, confirmation_view - -class CommentPostBadRequest(http.HttpResponseBadRequest): - """ - Response returned when a comment post is invalid. If ``DEBUG`` is on a - nice-ish error message will be displayed (for debugging purposes), but in - production mode a simple opaque 400 page will be displayed. - """ - def __init__(self, why): - super(CommentPostBadRequest, self).__init__() - if settings.DEBUG: - self.content = render_to_string("comments/400-debug.html", {"why": why}) - - -@require_POST -def post_comment(request, next=None, using=None): - """ - Post a comment. - - HTTP POST is required. If ``POST['submit'] == "preview"`` or if there are - errors a preview template, ``comments/preview.html``, will be rendered. - """ - # Fill out some initial data fields from an authenticated user, if present - data = request.POST.copy() - if request.user.is_authenticated(): - if not data.get('name', ''): - data["name"] = request.user.get_full_name() or request.user.get_username() - if not data.get('email', ''): - data["email"] = request.user.email - - # Look up the object we're trying to comment about - ctype = data.get("content_type") - object_pk = data.get("object_pk") - if ctype is None or object_pk is None: - return CommentPostBadRequest("Missing content_type or object_pk field.") - try: - model = apps.get_model(*ctype.split(".", 1)) - target = model._default_manager.using(using).get(pk=object_pk) - except TypeError: - return CommentPostBadRequest( - "Invalid content_type value: %r" % escape(ctype)) - except AttributeError: - return CommentPostBadRequest( - "The given content-type %r does not resolve to a valid model." % \ - escape(ctype)) - except ObjectDoesNotExist: - return CommentPostBadRequest( - "No object matching content-type %r and object PK %r exists." % \ - (escape(ctype), escape(object_pk))) - except (ValueError, ValidationError) as e: - return CommentPostBadRequest( - "Attempting go get content-type %r and object PK %r exists raised %s" % \ - (escape(ctype), escape(object_pk), e.__class__.__name__)) - - # Do we want to preview the comment? - preview = "preview" in data - - # Construct the comment form - form = django_comments.get_form()(target, data=data) - - # Check security information - if form.security_errors(): - return CommentPostBadRequest( - "The comment form failed security verification: %s" % \ - escape(str(form.security_errors()))) - - # If there are errors or if we requested a preview show the comment - if form.errors or preview: - template_list = [ - # These first two exist for purely historical reasons. - # Django v1.0 and v1.1 allowed the underscore format for - # preview templates, so we have to preserve that format. - "comments/%s_%s_preview.html" % (model._meta.app_label, model._meta.model_name), - "comments/%s_preview.html" % model._meta.app_label, - # Now the usual directory based template hierarchy. - "comments/%s/%s/preview.html" % (model._meta.app_label, model._meta.model_name), - "comments/%s/preview.html" % model._meta.app_label, - "comments/preview.html", - ] - return render_to_response( - template_list, { - "comment": form.data.get("comment", ""), - "form": form, - "next": data.get("next", next), - }, - RequestContext(request, {}) - ) - - # Otherwise create the comment - comment = form.get_comment_object() - comment.ip_address = request.META.get("REMOTE_ADDR", None) - if request.user.is_authenticated(): - comment.user = request.user - - # Signal that the comment is about to be saved - responses = signals.comment_will_be_posted.send( - sender=comment.__class__, - comment=comment, - request=request - ) - - for (receiver, response) in responses: - if response == False: - return CommentPostBadRequest( - "comment_will_be_posted receiver %r killed the comment" % receiver.__name__) - - # Save the comment and signal that it was saved - comment.save() - signals.comment_was_posted.send( - sender=comment.__class__, - comment=comment, - request=request - ) - - return next_redirect(request, fallback=next or 'comments-comment-done', - c=comment._get_pk_val()) - -comment_done = confirmation_view( - template="comments/posted.html", - doc="""Display a "comment was posted" success page.""" -) diff --git a/app/lib/django_comments_old/views/moderation.py b/app/lib/django_comments_old/views/moderation.py deleted file mode 100644 index b35626a..0000000 --- a/app/lib/django_comments_old/views/moderation.py +++ /dev/null @@ -1,165 +0,0 @@ -from __future__ import absolute_import - -from django import template -from django.conf import settings -from django.contrib.auth.decorators import login_required, permission_required -from django.shortcuts import get_object_or_404, render_to_response -from django.views.decorators.csrf import csrf_protect - -import django_comments -from django_comments import signals -from django_comments.views.utils import next_redirect, confirmation_view - -@csrf_protect -@login_required -def flag(request, comment_id, next=None): - """ - Flags a comment. Confirmation on GET, action on POST. - - Templates: :template:`comments/flag.html`, - Context: - comment - the flagged `comments.comment` object - """ - comment = get_object_or_404(django_comments.get_model(), pk=comment_id, site__pk=settings.SITE_ID) - - # Flag on POST - if request.method == 'POST': - perform_flag(request, comment) - return next_redirect(request, fallback=next or 'comments-flag-done', - c=comment.pk) - - # Render a form on GET - else: - return render_to_response('comments/flag.html', - {'comment': comment, "next": next}, - template.RequestContext(request) - ) - -@csrf_protect -@permission_required("django_comments.can_moderate") -def delete(request, comment_id, next=None): - """ - Deletes a comment. Confirmation on GET, action on POST. Requires the "can - moderate comments" permission. - - Templates: :template:`comments/delete.html`, - Context: - comment - the flagged `comments.comment` object - """ - comment = get_object_or_404(django_comments.get_model(), pk=comment_id, site__pk=settings.SITE_ID) - - # Delete on POST - if request.method == 'POST': - # Flag the comment as deleted instead of actually deleting it. - perform_delete(request, comment) - return next_redirect(request, fallback=next or 'comments-delete-done', - c=comment.pk) - - # Render a form on GET - else: - return render_to_response('comments/delete.html', - {'comment': comment, "next": next}, - template.RequestContext(request) - ) - -@csrf_protect -@permission_required("django_comments.can_moderate") -def approve(request, comment_id, next=None): - """ - Approve a comment (that is, mark it as public and non-removed). Confirmation - on GET, action on POST. Requires the "can moderate comments" permission. - - Templates: :template:`comments/approve.html`, - Context: - comment - the `comments.comment` object for approval - """ - comment = get_object_or_404(django_comments.get_model(), pk=comment_id, site__pk=settings.SITE_ID) - - # Delete on POST - if request.method == 'POST': - # Flag the comment as approved. - perform_approve(request, comment) - return next_redirect(request, fallback=next or 'comments-approve-done', - c=comment.pk) - - # Render a form on GET - else: - return render_to_response('comments/approve.html', - {'comment': comment, "next": next}, - template.RequestContext(request) - ) - -# The following functions actually perform the various flag/aprove/delete -# actions. They've been broken out into separate functions to that they -# may be called from admin actions. - -def perform_flag(request, comment): - """ - Actually perform the flagging of a comment from a request. - """ - flag, created = django_comments.models.CommentFlag.objects.get_or_create( - comment = comment, - user = request.user, - flag = django_comments.models.CommentFlag.SUGGEST_REMOVAL - ) - signals.comment_was_flagged.send( - sender = comment.__class__, - comment = comment, - flag = flag, - created = created, - request = request, - ) - -def perform_delete(request, comment): - flag, created = django_comments.models.CommentFlag.objects.get_or_create( - comment = comment, - user = request.user, - flag = django_comments.models.CommentFlag.MODERATOR_DELETION - ) - comment.is_removed = True - comment.save() - signals.comment_was_flagged.send( - sender = comment.__class__, - comment = comment, - flag = flag, - created = created, - request = request, - ) - - -def perform_approve(request, comment): - flag, created = django_comments.models.CommentFlag.objects.get_or_create( - comment = comment, - user = request.user, - flag = django_comments.models.CommentFlag.MODERATOR_APPROVAL, - ) - - comment.is_removed = False - comment.is_public = True - comment.save() - - signals.comment_was_flagged.send( - sender = comment.__class__, - comment = comment, - flag = flag, - created = created, - request = request, - ) - -# Confirmation views. - -flag_done = confirmation_view( - template = "comments/flagged.html", - doc = 'Displays a "comment was flagged" success page.' -) -delete_done = confirmation_view( - template = "comments/deleted.html", - doc = 'Displays a "comment was deleted" success page.' -) -approve_done = confirmation_view( - template = "comments/approved.html", - doc = 'Displays a "comment was approved" success page.' -) diff --git a/app/lib/django_comments_old/views/utils.py b/app/lib/django_comments_old/views/utils.py deleted file mode 100644 index 314ab8c..0000000 --- a/app/lib/django_comments_old/views/utils.py +++ /dev/null @@ -1,71 +0,0 @@ -""" -A few bits of helper functions for comment views. -""" - -import textwrap -try: - from urllib.parse import urlencode -except ImportError: # Python 2 - from urllib import urlencode - -from django.http import HttpResponseRedirect -from django.shortcuts import render_to_response, resolve_url -from django.template import RequestContext -from django.core.exceptions import ObjectDoesNotExist -from django.utils.http import is_safe_url - -import django_comments - -def next_redirect(request, fallback, **get_kwargs): - """ - Handle the "where should I go next?" part of comment views. - - The next value could be a - ``?next=...`` GET arg or the URL of a given view (``fallback``). See - the view modules for examples. - - Returns an ``HttpResponseRedirect``. - """ - next = request.POST.get('next') - if not is_safe_url(url=next, host=request.get_host()): - next = resolve_url(fallback) - - if get_kwargs: - if '#' in next: - tmp = next.rsplit('#', 1) - next = tmp[0] - anchor = '#' + tmp[1] - else: - anchor = '' - - joiner = ('?' in next) and '&' or '?' - next += joiner + urlencode(get_kwargs) + anchor - return HttpResponseRedirect(next) - -def confirmation_view(template, doc="Display a confirmation view."): - """ - Confirmation view generator for the "comment was - posted/flagged/deleted/approved" views. - """ - def confirmed(request): - comment = None - if 'c' in request.GET: - try: - comment = django_comments.get_model().objects.get(pk=request.GET['c']) - except (ObjectDoesNotExist, ValueError): - pass - return render_to_response(template, - {'comment': comment}, - context_instance=RequestContext(request) - ) - - confirmed.__doc__ = textwrap.dedent("""\ - %s - - Templates: :template:`%s`` - Context: - comment - The posted comment - """ % (doc, template) - ) - return confirmed diff --git a/app/photos/admin.py b/app/photos/admin.py index 3211a06..b69897a 100644 --- a/app/photos/admin.py +++ b/app/photos/admin.py @@ -26,7 +26,7 @@ class LuxVideoAdmin(OSMGeoAdmin): class LuxImageAdmin(OSMGeoAdmin): - list_display = ('pk', 'admin_thumbnail', 'pub_date', 'location') + list_display = ('pk', 'admin_thumbnail', 'pub_date', 'caption', 'location') list_filter = ('pub_date', 'location') search_fields = ['title', 'caption'] list_editable = ('location',) diff --git a/config/django.ini b/config/django.ini index bbb8413..a22d296 100644 --- a/config/django.ini +++ b/config/django.ini @@ -1,7 +1,6 @@ # django.ini file [uwsgi] -plugin = python # maximum number of processes processes = 4 max-requests = 5000 @@ -10,7 +9,7 @@ enable-threads = true uid = http gid = http -socket = /run/uwsgi/uwsgi.sock +socket = /tmp/uwsgi.sock chmod-socket = 664 chown-socket = http:http diff --git a/config/requirements.txt b/config/requirements.txt index 6e6bed2..64ccef5 100644 --- a/config/requirements.txt +++ b/config/requirements.txt @@ -1,44 +1,42 @@ beautifulsoup4==4.4.0 bleach==1.4.1 +certifi==2017.7.27.1 +chardet==3.0.4 decorator==4.0.4 -Django==1.9 -django-autocomplete-light==2.2.10 +Django==1.11.5 +django-autocomplete-light==3.2.10 django-bleach==0.3.0 -django-extensions==1.5.9 +django-debug-toolbar==1.8 +django-extensions==1.9.1 django-gravatar2==1.3.0 django-paypal==0.2.7 django-taggit==0.17.5 django-typogrify==1.3.2 -EbookLib==0.15 -facebook-sdk==1.0.0 -flickr-api==0.5 -flickrapi==2.1.2 +EbookLib==0.16 +facebook-sdk==2.0.0 +flickrapi==2.3 html5lib==0.999999 -ipython==4.0.0 -ipython-genutils==0.1.0 -Jinja2==2.8 -jsmin==2.1.4 -lxml==3.4.0 -Markdown==2.6.2 -MarkupSafe==0.23 +idna==2.6 +Jinja2==2.9.6 +jsmin==2.2.2 +lxml==4.0.0 +Markdown==2.6.9 +MarkupSafe==1.0 medium==0.3.0 -oauth==1.0.1 -oauthlib==1.1.2 -path.py==8.1.2 -pexpect==4.0.1 -pickleshare==0.5 -Pillow==3.1.1 -psycopg2==2.6.1 -ptyprocess==0.5 -Pygments==2.0.2 -python-resize-image==1.1.3 -requests==2.7.0 -requests-oauthlib==0.5.0 -requests-toolbelt==0.6.0 -simplegeneric==0.8.1 -six==1.10.0 +oauthlib==2.0.4 +olefile==0.44 +Pillow==4.2.1 +psycopg2==2.7.3.1 +PyExifTool==0.1 +python-resize-image==1.1.11 +pytz==2017.2 +requests==2.18.4 +requests-oauthlib==0.8.0 +requests-toolbelt==0.8.0 +six==1.11.0 smartypants==1.8.6 -traitlets==4.0.0 -twython==3.3.0 +sqlparse==0.2.3 +twython==3.6.0 typogrify==2.0.7 -uWSGI==2.0.14 +urllib3==1.22 +uWSGI==2.0.15 |