Commits

Yorgos Pagles committed dbeaec9

Fixed newsletter

  • Participants
  • Parent commits 71bb733

Comments (0)

Files changed (10)

.#requirements.txt

+pagles@Yorgoss-MacBook-Pro.local.91983

newsletter/fixtures/default_templates.json

-[{"pk": 1, "model": "newsletter.emailtemplate", "fields": {"action": "message", "text": "++++++++++++++++++++\r\n\r\n{{ newsletter.title }}: {{ message.title }}\r\n\r\n++++++++++++++++++++\r\n\r\n{% for article in message.articles.all %}\r\n{{ article.title }}\r\n{{ article.text|striptags|safe }}\r\n\r\n{% endfor %}\r\n\r\n++++++++++++++++++++\r\n\r\nUnsubscribe: http://{{ site }}{% url newsletter_unsubscribe_request newsletter.slug %}", "subject": "{{ newsletter.title }} - {{ message.title }}", "html": "{% load thumbnail %}<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\r\n   \"http://www.w3.org/TR/html4/strict.dtd\">\r\n\r\n<html lang=\"en\">\r\n<head>\r\n\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\r\n\t<title>{{ newsletter.title }}: {{ message.title }}</title>\r\n</head>\r\n<body>\r\n    <h1>{{ newsletter.title }}</h1>\r\n    <h2>{{ message.title }}</h2>\r\n    {% for article in message.articles.all %}\r\n        <h3>{{ article.title }}</h3>\r\n        \r\n        {% thumbnail article.image \"200x200\" as image %}\r\n            <img src=\"http://{{ site.domain }}{{ image.url }}\" width=\"{{ image.width }}\" height=\"{{ image.height }}\">\r\n        {% endthumbnail %}\r\n\r\n        <div>{{ article.text|safe }}</div>\r\n        \r\n        {% if article.url %}\r\n            <div><a href=\"{{ article.url }}\">Read more</div></a>\r\n        {% endif %}\r\n    {% endfor %}\r\n    \r\n    <ul>\r\n        {% if submission.publish %}\r\n        <li><a href=\"http://{{ site.domain }}{{ submission.get_absolute_url }}\">Read message online</a></li>\r\n        {% endif %}\r\n        <li><a href=\"http://{{ site.domain }}{% url newsletter_unsubscribe_request newsletter.slug %}\">Unsubscribe</a></li>\r\n    </ul>\r\n</body>\r\n</html>", "title": "Default"}}, {"pk": 2, "model": "newsletter.emailtemplate", "fields": {"action": "subscribe", "text": "Dear {{ subscription.name }},\r\n\r\nyou, or someone in your name requested a subscription to {{ newsletter.title }}.\r\n\r\nIf you would like to confirm your subscription, please follow this activation link:\r\nhttp://{{ site.domain }}{{ subscription.subscribe_activate_url }}\r\n\r\nKind regards,\r\n{{ newsletter.sender }}", "subject": "{{ newsletter.title }} - Confirm subscription", "html": "", "title": "Default"}}, {"pk": 3, "model": "newsletter.emailtemplate", "fields": {"action": "unsubscribe", "text": "Dear {{ subscription.name }},\r\n\r\nyou, or someone in your name requested unsubscription from {{ newsletter.title }}.\r\n\r\nIf you would like to confirm your subscription, please follow this activation link:\r\nhttp://{{ site.domain }}{{ subscription.unsubscribe_activate_url }}\r\n\r\nKind regards,\r\n{{ newsletter.sender }}", "subject": "{{ newsletter.title }} - Confirm unsubscription", "html": "", "title": "Default"}}, {"pk": 4, "model": "newsletter.emailtemplate", "fields": {"action": "update", "text": "Dear {{ subscription.name }},\r\n\r\nyou, or someone in your name requested updating your personal information for {{ newsletter.title }}.\r\n\r\nTo make changes to your information in our database, please follow this activation link:\r\nhttp://{{ site.domain }}{{ subscription.update_activate_url }}\r\n\r\nKind regards,\r\n{{ newsletter.sender }}", "subject": "{{ newsletter.title }} - Update information", "html": "", "title": "Default"}}]
+[{"pk": 1, "model": "newsletter.emailtemplate", "fields": {"action": "message", "text": "++++++++++++++++++++\r\n\r\n{{ newsletter.title }}: {{ message.title }}\r\n\r\n++++++++++++++++++++\r\n\r\n{% for article in message.articles.all %}\r\n{{ article.title }}\r\n{{ article.text|striptags|safe }}\r\n\r\n{% endfor %}\r\n\r\n++++++++++++++++++++\r\n\r\nUnsubscribe: http://{{ site }}{% url 'newsletter_unsubscribe_request' newsletter.slug %}", "subject": "{{ newsletter.title }} - {{ message.title }}", "html": "{% load thumbnail %}<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\r\n   \"http://www.w3.org/TR/html4/strict.dtd\">\r\n\r\n<html lang=\"en\">\r\n<head>\r\n\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\r\n\t<title>{{ newsletter.title }}: {{ message.title }}</title>\r\n</head>\r\n<body>\r\n    <h1>{{ newsletter.title }}</h1>\r\n    <h2>{{ message.title }}</h2>\r\n    {% for article in message.articles.all %}\r\n        <h3>{{ article.title }}</h3>\r\n        \r\n        {% thumbnail article.image \"200x200\" as image %}\r\n            <img src=\"http://{{ site.domain }}{{ image.url }}\" width=\"{{ image.width }}\" height=\"{{ image.height }}\">\r\n        {% endthumbnail %}\r\n\r\n        <div>{{ article.text|safe }}</div>\r\n        \r\n        {% if article.url %}\r\n            <div><a href=\"{{ article.url }}\">Read more</div></a>\r\n        {% endif %}\r\n    {% endfor %}\r\n    \r\n    <ul>\r\n        {% if submission.publish %}\r\n        <li><a href=\"http://{{ site.domain }}{{ submission.get_absolute_url }}\">Read message online</a></li>\r\n        {% endif %}\r\n        <li><a href=\"http://{{ site.domain }}{% url 'newsletter_unsubscribe_request' newsletter.slug %}\">Unsubscribe</a></li>\r\n    </ul>\r\n</body>\r\n</html>", "title": "Default"}}, {"pk": 2, "model": "newsletter.emailtemplate", "fields": {"action": "subscribe", "text": "Dear {{ subscription.name }},\r\n\r\nyou, or someone in your name requested a subscription to {{ newsletter.title }}.\r\n\r\nIf you would like to confirm your subscription, please follow this activation link:\r\nhttp://{{ site.domain }}{{ subscription.subscribe_activate_url }}\r\n\r\nKind regards,\r\n{{ newsletter.sender }}", "subject": "{{ newsletter.title }} - Confirm subscription", "html": "", "title": "Default"}}, {"pk": 3, "model": "newsletter.emailtemplate", "fields": {"action": "unsubscribe", "text": "Dear {{ subscription.name }},\r\n\r\nyou, or someone in your name requested unsubscription from {{ newsletter.title }}.\r\n\r\nIf you would like to confirm your subscription, please follow this activation link:\r\nhttp://{{ site.domain }}{{ subscription.unsubscribe_activate_url }}\r\n\r\nKind regards,\r\n{{ newsletter.sender }}", "subject": "{{ newsletter.title }} - Confirm unsubscription", "html": "", "title": "Default"}}, {"pk": 4, "model": "newsletter.emailtemplate", "fields": {"action": "update", "text": "Dear {{ subscription.name }},\r\n\r\nyou, or someone in your name requested updating your personal information for {{ newsletter.title }}.\r\n\r\nTo make changes to your information in our database, please follow this activation link:\r\nhttp://{{ site.domain }}{{ subscription.update_activate_url }}\r\n\r\nKind regards,\r\n{{ newsletter.sender }}", "subject": "{{ newsletter.title }} - Update information", "html": "", "title": "Default"}}]

newsletter/templates/admin/newsletter/message/preview.html

 <h1>{% trans "Preview message" %}</h1>
 <div id="content-main">
   <ul class="object-tools">
-    <li><a href="{% url admin:newsletter_message_change message.id %}">{% trans "Change" %}</a></li>
-    <li><a href="{% url admin:newsletter_message_submit message.id %}">{% trans "Create submission" %}</a></li>
+    <li><a href="{% url 'admin:newsletter_message_change' message.id %}">{% trans "Change" %}</a></li>
+    <li><a href="{% url 'admin:newsletter_message_submit' message.id %}">{% trans "Create submission" %}</a></li>
   </ul>
     {% if message.newsletter.message_template.html %}
     <h4>{% trans "HTML" %}</h4>
-    <iframe src ="{% url admin:newsletter_message_preview_html message.id %}" width="960px" height="720px"></iframe>
+    <iframe src ="{% url 'admin:newsletter_message_preview_html' message.id %}" width="960px" height="720px"></iframe>
     {% endif %}
 
     <h4>{% trans "Text" %}</h4>
-    <iframe src ="{% url admin:newsletter_message_preview_text message.id %}" width="960px" height="720px"></iframe>
+    <iframe src ="{% url 'admin:newsletter_message_preview_text' message.id %}" width="960px" height="720px"></iframe>
 </div>
 <br/>
 <br/>

newsletter/templates/admin/newsletter/submission/change_form.html

 
 {% block extrahead %}
 {{ block.super }}
-<script src="{% url admin:newsletter_js18n %}" type="text/javascript"></script>
+<script src="{% url 'admin:newsletter_js18n' %}" type="text/javascript"></script>
 <script src="{{ STATIC_URL }}newsletter/admin/js/subscriber_lookup.js" type="text/javascript"></script>
 <script src="{{ STATIC_URL }}newsletter/admin/js/submit_interface.js" type="text/javascript"></script>
 {% endblock %}

newsletter/templates/newsletter/newsletter_detail.html

         <th>{% trans "Newsletter" %} {{ object.title }}</th>
     </tr>
     <tr>
-        <td><a href="{% url newsletter_subscribe_request object.slug %}">Subscribe</a></td>
+        <td><a href="{% url 'newsletter_subscribe_request' object.slug %}">Subscribe</a></td>
     </tr>
     {% if not user.is_authenticated %}
     <tr>
-        <td><a href="{% url newsletter_update_request object.slug %}">Update</a></td>
+        <td><a href="{% url 'newsletter_update_request' object.slug %}">Update</a></td>
     </tr>
     {% endif %}
     <tr>
-        <td><a href="{% url newsletter_unsubscribe_request object.slug %}">Unsubscribe</a></td>
+        <td><a href="{% url 'newsletter_unsubscribe_request' object.slug %}">Unsubscribe</a></td>
     </tr>
     <tr>
-        <td><a href="{% url newsletter_archive object.slug %}">Archive</a></td>
+        <td><a href="{% url 'newsletter_archive' object.slug %}">Archive</a></td>
     </tr>
     <tr>
         <td><a href="../">Back to list</a></td>

newsletter/templates/newsletter/newsletter_list.html

     {% for form in formset.forms %}
       <tr>
         <td>{{ form.id }}{{ form.newsletter }}
-<a href="{% url newsletter_detail form.instance.newsletter.slug %}">{{ form.instance.newsletter.title }}</a></td>
+<a href="{% url 'newsletter_detail' form.instance.newsletter.slug %}">{{ form.instance.newsletter.title }}</a></td>
         <td>{{ form.subscribed }}</td>
       </tr>
     {% endfor %}
     </tr>
     {% for newsletter in object_list %}
     <tr>
-        <td><a href="{% url newsletter_detail newsletter.slug %}">{{ newsletter.title }}</a></td>
+        <td><a href="{% url 'newsletter_detail' newsletter.slug %}">{{ newsletter.title }}</a></td>
     </tr>
     {% endfor %}
 </table>

newsletter/templates/newsletter/subscription_subscribe_user.html

 </ul>
 {% else %}
 {% trans "Do you want to subscribe to this newsletter?" %}
-<form enctype="multipart/form-data" method="post" action="{% url newsletter_subscribe_confirm newsletter.slug %}">
+<form enctype="multipart/form-data" method="post" action="{% url 'newsletter_subscribe_confirm' newsletter.slug %}">
     {% csrf_token %}
     <p><input id="id_submit" name="submit" value="{% trans "Subscribe" %}" type="submit" /></p>
 </form>

newsletter/templates/newsletter/subscription_unsubscribe_user.html

 {% else %}
 
 {% trans "Do you want to unsubscribe from this newsletter?" %}
-<form enctype="multipart/form-data" method="post" action="{% url newsletter_unsubscribe_confirm newsletter.slug %}">
+<form enctype="multipart/form-data" method="post" action="{% url 'newsletter_unsubscribe_confirm' newsletter.slug %}">
     {% csrf_token %}
     <p><input id="id_submit" name="submit" value="{% trans "Unsubscribe" %}" type="submit" /></p>
 </form>

newsletter/views.py

+import datetime
 import logging
 
 logger = logging.getLogger(__name__)
 
-from django.core.exceptions import ValidationError
+from django.core.exceptions import ValidationError, ObjectDoesNotExist
 from django.conf import settings
+from django.core.xheaders import populate_xheaders
 
-from django.template import RequestContext, Context
+from django.template import loader, RequestContext, Context
 
 from django.shortcuts import get_object_or_404, render_to_response
 from django.http import HttpResponse, Http404
 
-from django.views.generic import list_detail, date_based
-
 from django.contrib import messages
 from django.contrib.sites.models import Site
 from django.contrib.auth.decorators import login_required
 )
 
 
+def archive_index(request, queryset, date_field, num_latest=15,
+                  template_name=None, template_loader=loader,
+                  extra_context=None, allow_empty=True,
+                  context_processors=None, mimetype=None,
+                  allow_future=False, template_object_name='latest'):
+    """
+    Generic top-level archive of date-based objects.
+
+    Templates: ``<app_label>/<model_name>_archive.html``
+    Context:
+        date_list
+            List of years
+        latest
+            Latest N (defaults to 15) objects by date
+    """
+    if extra_context is None:
+        extra_context = {}
+    model = queryset.model
+    if not allow_future:
+        queryset = queryset.filter(**{'%s__lte' % date_field: datetime.datetime.now()})
+    date_list = queryset.dates(date_field, 'year')[::-1]
+    if not date_list and not allow_empty:
+        raise Http404("No %s available" % model._meta.verbose_name)
+
+    if date_list and num_latest:
+        latest = queryset.order_by('-' + date_field)[:num_latest]
+    else:
+        latest = None
+
+    if not template_name:
+        template_name = "%s/%s_archive.html" % (model._meta.app_label, model._meta.object_name.lower())
+    t = template_loader.get_template(template_name)
+    c = RequestContext(request, {
+        'date_list': date_list,
+        template_object_name: latest,
+    }, context_processors)
+    for key, value in extra_context.items():
+        if callable(value):
+            c[key] = value()
+        else:
+            c[key] = value
+    return HttpResponse(t.render(c), mimetype=mimetype)
+
+
+def object_detail(request, queryset, object_id=None, slug=None,
+                  slug_field='slug', template_name=None,
+                  template_name_field=None, template_loader=loader,
+                  extra_context=None, context_processors=None,
+                  template_object_name='object', mimetype=None):
+    """
+    Generic detail of an object.
+
+    Templates: ``<app_label>/<model_name>_detail.html``
+    Context:
+        object
+            the object
+    """
+    if extra_context is None:
+        extra_context = {}
+    model = queryset.model
+    if object_id:
+        queryset = queryset.filter(pk=object_id)
+    elif slug and slug_field:
+        queryset = queryset.filter(**{slug_field: slug})
+    else:
+        raise AttributeError("Generic detail view must be called with either an object_id or a slug/slug_field.")
+    try:
+        obj = queryset.get()
+    except ObjectDoesNotExist:
+        raise Http404("No %s found matching the query" % (model._meta.verbose_name))
+    if not template_name:
+        template_name = "%s/%s_detail.html" % (model._meta.app_label, model._meta.object_name.lower())
+    if template_name_field:
+        template_name_list = [getattr(obj, template_name_field), template_name]
+        t = template_loader.select_template(template_name_list)
+    else:
+        t = template_loader.get_template(template_name)
+    c = RequestContext(request, {
+        template_object_name: obj,
+    }, context_processors)
+    for key, value in extra_context.items():
+        if callable(value):
+            c[key] = value()
+        else:
+            c[key] = value
+    response = HttpResponse(t.render(c), mimetype=mimetype)
+    populate_xheaders(request, response, model, getattr(obj, obj._meta.pk.name))
+    return response
+
+
+def object_list(request, queryset, paginate_by=None, page=None,
+                allow_empty=True, template_name=None, template_loader=loader,
+                extra_context=None, context_processors=None,
+                template_object_name='object', mimetype=None):
+    """
+    Generic list of objects.
+
+    Templates: ``<app_label>/<model_name>_list.html``
+    Context:
+        object_list
+            list of objects
+        is_paginated
+            are the results paginated?
+        results_per_page
+            number of objects per page (if paginated)
+        has_next
+            is there a next page?
+        has_previous
+            is there a prev page?
+        page
+            the current page
+        next
+            the next page
+        previous
+            the previous page
+        pages
+            number of pages, total
+        hits
+            number of objects, total
+        last_on_page
+            the result number of the last of object in the
+            object_list (1-indexed)
+        first_on_page
+            the result number of the first object in the
+            object_list (1-indexed)
+        page_range:
+            A list of the page numbers (1-indexed).
+    """
+    if extra_context is None:
+        extra_context = {}
+    queryset = queryset._clone()
+    if paginate_by:
+        paginator = Paginator(queryset,
+                              paginate_by,
+                              allow_empty_first_page=allow_empty)
+        if not page:
+            page = request.GET.get('page', 1)
+        try:
+            page_number = int(page)
+        except ValueError:
+            if page == 'last':
+                page_number = paginator.num_pages
+            else:
+                # Page is not 'last', nor can it be converted to an int.
+                raise Http404
+        try:
+            page_obj = paginator.page(page_number)
+        except InvalidPage:
+            raise Http404
+        c = RequestContext(request, {
+            '%s_list' % template_object_name: page_obj.object_list,
+            'paginator': paginator,
+            'page_obj': page_obj,
+            'is_paginated': page_obj.has_other_pages(),
+
+            # Legacy template context stuff. New templates should use page_obj
+            # to access this instead.
+            'results_per_page': paginator.per_page,
+            'has_next': page_obj.has_next(),
+            'has_previous': page_obj.has_previous(),
+            'page': page_obj.number,
+            'next': page_obj.next_page_number(),
+            'previous': page_obj.previous_page_number(),
+            'first_on_page': page_obj.start_index(),
+            'last_on_page': page_obj.end_index(),
+            'pages': paginator.num_pages,
+            'hits': paginator.count,
+            'page_range': paginator.page_range,
+        }, context_processors)
+    else:
+        c = RequestContext(request, {
+            '%s_list' % template_object_name: queryset,
+            'paginator': None,
+            'page_obj': None,
+            'is_paginated': False,
+        }, context_processors)
+        if not allow_empty and len(queryset) == 0:
+            raise Http404
+    for key, value in extra_context.items():
+        if callable(value):
+            c[key] = value()
+        else:
+            c[key] = value
+    if not template_name:
+        model = queryset.model
+        template_name = "%s/%s_list.html" % (model._meta.app_label, model._meta.object_name.lower())
+    t = template_loader.get_template(template_name)
+    return HttpResponse(t.render(c), mimetype=mimetype)
+
 def newsletter_list(request):
     newsletters = Newsletter.on_site.filter(visible=True)
 
     else:
         formset = None
 
-    return list_detail.object_list(
+    return object_list(
         request, newsletters, extra_context={'formset': formset})
 
 
 def newsletter_detail(request, newsletter_slug):
     newsletters = Newsletter.on_site.filter(visible=True)
 
-    return list_detail.object_detail(
+    return object_detail(
         request, newsletters, slug=newsletter_slug)
 
 
         newsletter=my_newsletter, publish=True
     )
 
-    return date_based.archive_index(
+    return archive_index(
         request,
         queryset=submissions,
         date_field='publish_date',
 DATABASES = {
     'default' : {
-        'ENGINE': 'django.db.backends.sqlite3'
+        'ENGINE': 'django.db.backends.postgresql_psycopg2',
+        'NAME': 'django-newsletter-tests'
     }
 }
 
 
 # Enable time-zone support for Django 1.4 (ignored in older versions)
 USE_TZ = True
+
+SECRET_KEY = 'tests-key'