summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorluxagraf <sng@luxagraf.net>2017-10-14 11:36:20 -0500
committerluxagraf <sng@luxagraf.net>2017-10-14 11:36:20 -0500
commitbd1adb4927695ed0ce3ac94d90c68bd61e440275 (patch)
treef014fa16a64eb55e62ecb92c62a4e8186cd318a4
parentcbadfff80be33b4ec67da57585451884c6378380 (diff)
updated comments app and added caption to photo list view
-rw-r--r--app/lib/django_comments/__init__.py13
-rw-r--r--app/lib/django_comments/abstracts.py7
-rw-r--r--app/lib/django_comments/forms.py10
-rw-r--r--app/lib/django_comments/locale/eo/LC_MESSAGES/django.mobin4913 -> 5077 bytes
-rw-r--r--app/lib/django_comments/locale/eo/LC_MESSAGES/django.po14
-rw-r--r--app/lib/django_comments/locale/ko/LC_MESSAGES/django.mobin5400 -> 5403 bytes
-rw-r--r--app/lib/django_comments/locale/ko/LC_MESSAGES/django.po9
-rw-r--r--app/lib/django_comments/locale/nl/LC_MESSAGES/django.mobin5057 -> 5376 bytes
-rw-r--r--app/lib/django_comments/locale/nl/LC_MESSAGES/django.po18
-rw-r--r--app/lib/django_comments/locale/sq/LC_MESSAGES/django.mobin5263 -> 5374 bytes
-rw-r--r--app/lib/django_comments/locale/sq/LC_MESSAGES/django.po11
-rw-r--r--app/lib/django_comments/moderation.py5
-rw-r--r--app/lib/django_comments/templatetags/comments.py9
-rw-r--r--app/lib/django_comments/views/comments.py17
-rw-r--r--app/lib/django_comments/views/moderation.py14
-rw-r--r--app/lib/django_comments_old/__init__.py91
-rw-r--r--app/lib/django_comments_old/admin.py87
-rw-r--r--app/lib/django_comments_old/akismet.py105
-rw-r--r--app/lib/django_comments_old/feeds.py32
-rw-r--r--app/lib/django_comments_old/forms.py197
-rw-r--r--app/lib/django_comments_old/managers.py22
-rw-r--r--app/lib/django_comments_old/models.py204
-rw-r--r--app/lib/django_comments_old/moderation.py357
-rw-r--r--app/lib/django_comments_old/signals.py21
-rw-r--r--app/lib/django_comments_old/templatetags/__init__.py0
-rw-r--r--app/lib/django_comments_old/templatetags/comments.py334
-rw-r--r--app/lib/django_comments_old/urls.py18
-rw-r--r--app/lib/django_comments_old/views/__init__.py0
-rw-r--r--app/lib/django_comments_old/views/comments.py140
-rw-r--r--app/lib/django_comments_old/views/moderation.py165
-rw-r--r--app/lib/django_comments_old/views/utils.py71
-rw-r--r--app/photos/admin.py2
-rw-r--r--config/django.ini3
-rw-r--r--config/requirements.txt62
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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
index 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
Binary files differ
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