GithubHelp home page GithubHelp logo

jazzband / django-newsletter Goto Github PK

View Code? Open in Web Editor NEW
827.0 30.0 199.0 4.68 MB

An email newsletter application for the Django web application framework, including an extended admin interface, web (un)subscription, dynamic e-mail templates, an archive and HTML email support.

License: GNU Affero General Public License v3.0

Python 90.94% JavaScript 0.94% HTML 8.12%
django python newsletter

django-newsletter's Introduction

django-newsletter

image

Supported Python versions

Supported Django versions

GitHub Actions

image

Jazzband

Newsletter application for the Django web framework.

What is it?

Django app for managing multiple mass-mailing lists with both plaintext as well as HTML templates with rich text widget integration, images and a smart queueing system all right from the admin interface.

Status

We are currently using this package in several large to medium scale production environments, but it should be considered a permanent work in progress.

Documentation

Extended documentation is available on Read the Docs.

Translations

Strings have been fully translated to a lot of languages with many more on their way.

image

Contributions to translations are welcome through Transifex. Strings will be included as soon as near-full coverage is reached.

Compatibility

Currently, django-newsletter officially supports Django 2.2.x LTS, 3.1.x and 3.2.x and Python 3.7 through 3.10.

Requirements

Please refer to requirements.txt for an updated list of required packages.

Tests

Fairly extensive tests are available for internal frameworks, web (un)subscription and mail sending. Sending a newsletter to large groups of recipients (+15k) has been confirmed to work in multiple production environments. Tests for pull req's and the master branch are automatically run through GitHub Actions.

Contributing

Want to contribute, great!

Please refer to the issues on GitHub and read CONTRIBUTING.rst .

Feedback

If you find any bugs or have feature request for django-newsletter, don't hesitate to open up an issue on GitHub (but please make sure your issue hasn't been noticed before, finding duplicates is a waste of time). When modifying or adding features to django-newsletter in a fork, be sure to let me know what you're building and how you're building it. That way we can coordinate whether, when and how it will end up in the main fork and (eventually) an official release.

In general: thanks for the support, feedback, patches and code that's been flowing in over the years! Django has a truly great community. <3

License

This application is released under the GNU Affero General Public License version 3.

django-newsletter's People

Contributors

andreguerra123 avatar bashar avatar bld2104 avatar claudep avatar dependabot[bot] avatar dokterbob avatar dsanders11 avatar fearless-spider avatar fishdude avatar flupzor avatar frennkie avatar gabn88 avatar hramezani avatar hugovk avatar isaac-jordan avatar jezdez avatar jkuczm avatar jnns avatar manikos avatar mpyrev avatar muellermartin avatar newearthmartin avatar null-none avatar pcraston avatar procmail avatar redvasily avatar sergei-maertens avatar smithdc1 avatar thecardcheat avatar torhve avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-newsletter's Issues

Issues with default subscribe confirmation template

The default subscribe confirmation template lives in the database instead of templates/newsletter, so templates/newsletter/activation_email*.txt should be dropped (I was very confused by that)

Additionally, the {{ subscription.name }} should be replaced by {{ subscription.name|default:"Sir/Madam" }}.

Text only emails

Is there a way to send text only emails?

With database email templates one could leave html field on EmailTemplate blank.
With file based templates I guess from the code in models.py:

        try:
            html_template = select_template([
                template_root + '%(action)s.html' % template_subst,
                template_root + '%(newsletter)s/%(action)s.html' % template_subst
            ])

        except TemplateDoesNotExist:
            # HTML templates are not required
            html_template = None

decision whether send HTML version of emails is supposed to be related to template existence, but since default HTML templates are shipped with django-newsletter they always exist. Currently I see only one way to send text only emails, it can be done by deleting default HTML templates from django-newsletter, but that's hacky.

If control over emails is supposed to remain as granular as in previous version, I think that four additional BooleanFIelds on Newsletter model are needed. Each would determine whether to send HTML version of email for particular message_type. Or maybe like e.g. in django-cms use CharFields with template choices set in settings.

Factor out django-extensions 'cron in favor of Django mangement command

Years ago it seemed as though django-extensions (otherwise excellent) cron mechanism was going to be the de-facto standard for Django. In the end, this was not the case. It is a large dependency and we should aim to factor it out.

Instead, let's just make a generic Django management command.

Newsletter uses site manager as 'objects'

The Newsletter-object uses the SiteManager by default as objects. This is bad, because not selecting the current site in the admin makes a Newsletter disappear.

Suggested solution: define a second in_site manager as SiteManager and use it everywhere the user interfaces with the software. This way, the admin will still use the objects manager.

Note: make sure you define the objects manager explicitly after having defined a second manager.

TemplateSyntaxError: Caught NoReverseMatch while rendering: Reverse for 'imperavi-upload-image' with arguments '()' and keyword arguments '{'upload_path': 'imperavi/'}' not found.

Hi

Created a new project and then a new app for the same with no extra code at all except the app for the news

Thanks
Subramanyam

django.template.base.TemplateSyntaxError

TemplateSyntaxError: Caught NoReverseMatch while rendering: Reverse for 'imperavi-upload-image' with arguments '()' and keyword arguments '{'upload_path': 'imperavi/'}' not found.
Traceback (most recent call last)

This is the Copy/Paste friendly version of the traceback. You can also paste this traceback into the public lodgeit pastebin:

Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/django/contrib/staticfiles/handlers.py", line 68, in call
return self.application(environ, start_response)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/staticfiles/handlers.py", line 68, in call
return self.application(environ, start_response)
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/wsgi.py", line 272, in call
response = self.get_response(request)
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 169, in get_response
response = self.handle_uncaught_exception(request, resolver, sys.exc_info())
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 203, in handle_uncaught_exception
return debug.technical_500_response(request, _exc_info)
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 111, in get_response
response = callback(request, *callback_args, *_callback_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py", line 307, in wrapper
return self.admin_site.admin_view(view)(_args, *_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py", line 93, in _wrapped_view
response = view_func(request, _args, *_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/views/decorators/cache.py", line 79, in _wrapped_view_func
response = view_func(request, _args, *_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/sites.py", line 197, in inner
return view(request, _args, *_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py", line 28, in _wrapper
return bound_func(_args, *_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py", line 93, in _wrapped_view
response = view_func(request, _args, *_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/utils/decorators.py", line 24, in bound_func
return func(self, _args2, *_kwargs2)
File "/usr/local/lib/python2.7/dist-packages/django/db/transaction.py", line 217, in inner
res = func(_args, *_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py", line 938, in add_view
return self.render_change_form(request, context, form_url=form_url, add=True)
File "/usr/local/lib/python2.7/dist-packages/django/contrib/admin/options.py", line 708, in render_change_form
], context, context_instance=context_instance)
File "/usr/local/lib/python2.7/dist-packages/django/shortcuts/init.py", line 20, in render_to_response
return HttpResponse(loader.render_to_string(_args, *_kwargs), *_httpresponse_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader.py", line 188, in render_to_string
return t.render(context_instance)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py", line 123, in render
return self._render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py", line 117, in _render
return self.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py", line 744, in render
bits.append(self.render_node(node, context))
File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py", line 73, in render_node
result = node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader_tags.py", line 127, in render
return compiled_parent._render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py", line 117, in _render
return self.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py", line 744, in render
bits.append(self.render_node(node, context))
File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py", line 73, in render_node
result = node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader_tags.py", line 127, in render
return compiled_parent._render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py", line 117, in _render
return self.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py", line 744, in render
bits.append(self.render_node(node, context))
File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py", line 73, in render_node
result = node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader_tags.py", line 127, in render
return compiled_parent._render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py", line 117, in _render
return self.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py", line 744, in render
bits.append(self.render_node(node, context))
File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py", line 73, in render_node
result = node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader_tags.py", line 64, in render
result = block.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py", line 744, in render
bits.append(self.render_node(node, context))
File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py", line 73, in render_node
result = node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/defaulttags.py", line 227, in render
nodelist.append(node.render(context))
File "/usr/local/lib/python2.7/dist-packages/django/template/loader_tags.py", line 170, in render
return self.render_template(template, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader_tags.py", line 141, in render_template
output = template.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py", line 123, in render
return self._render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py", line 117, in _render
return self.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py", line 744, in render
bits.append(self.render_node(node, context))
File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py", line 73, in render_node
result = node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/defaulttags.py", line 227, in render
nodelist.append(node.render(context))
File "/usr/local/lib/python2.7/dist-packages/django/template/defaulttags.py", line 227, in render
nodelist.append(node.render(context))
File "/usr/local/lib/python2.7/dist-packages/django/template/loader_tags.py", line 159, in render
return self.render_template(self.template, context)
File "/usr/local/lib/python2.7/dist-packages/django/template/loader_tags.py", line 141, in render_template
output = template.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py", line 123, in render
return self._render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py", line 117, in _render
return self.nodelist.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py", line 744, in render
bits.append(self.render_node(node, context))
File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py", line 73, in render_node
result = node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/defaulttags.py", line 227, in render
nodelist.append(node.render(context))
File "/usr/local/lib/python2.7/dist-packages/django/template/defaulttags.py", line 227, in render
nodelist.append(node.render(context))
File "/usr/local/lib/python2.7/dist-packages/django/template/defaulttags.py", line 313, in render
return self.nodelist_false.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py", line 744, in render
bits.append(self.render_node(node, context))
File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py", line 73, in render_node
result = node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/defaulttags.py", line 313, in render
return self.nodelist_false.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/base.py", line 744, in render
bits.append(self.render_node(node, context))
File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py", line 73, in render_node
result = node.render(context)
File "/usr/local/lib/python2.7/dist-packages/django/template/debug.py", line 92, in render
output = force_unicode(output)
File "/usr/local/lib/python2.7/dist-packages/django/utils/encoding.py", line 71, in force_unicode
s = unicode(s)
File "/usr/local/lib/python2.7/dist-packages/django/forms/forms.py", line 408, in unicode
return self.as_widget()
File "/usr/local/lib/python2.7/dist-packages/django/forms/forms.py", line 439, in as_widget
return widget.render(name, self.value(), attrs=attrs)
File "/usr/local/lib/python2.7/dist-packages/imperavi/widget.py", line 29, in render
'imageUpload': reverse('imperavi-upload-image', kwargs={'upload_path': self.upload_path}),
File "/usr/local/lib/python2.7/dist-packages/django/core/urlresolvers.py", line 391, in reverse
*args, *_kwargs)))
File "/usr/local/lib/python2.7/dist-packages/django/core/urlresolvers.py", line 337, in reverse
"arguments '%s' not found." % (lookup_view_s, args, kwargs))
TemplateSyntaxError: Caught NoReverseMatch while rendering: Reverse for 'imperavi-upload-image' with arguments '()' and keyword arguments '{'upload_path': 'imperavi/'}' not found.

The debugger caught an exception in your WSGI application. You can now look at the traceback which led to the error.

To switch between the interactive traceback and the plaintext one, you can click on the "Traceback" headline. From the text traceback you can also create a paste of it. For code execution mouse-over the frame you want to debug and click on the console icon on the right side.

You can execute arbitrary Python code in the stack frames and there are some extra helpers available for introspection:

dump() shows all variables in the frame
dump(obj) dumps all that's known about the object

Brought to you by DON'T PANIC, your friendly Werkzeug powered traceback interpreter.

2.) Last frame

dump()
Local variables in frame
self <RegexURLResolver newss.urls (None:None) ^/>
args ()
m None
lookup_view_s 'imperavi-upload-image'
n None
possibilities []
lookup_view 'imperavi-upload-image'
kwargs {'upload_path': 'imperavi/'}

Full PEP8 compliance

As it seems, a lot of the (older) code is still not PEP8 compliant. This appears to me as something that has to be fixed.

Newsletters not visible after creation

Creating a new Newsletter in the admin site does not appear to work. After successfully adding a new Newsletter, I am taken to the (empty) list, with a success message.

If I try to recreate the same Newsletter I get a key error saying the slug is already in use.

Testsuite error when django.contrib.sites is not enabled

The testsuite throws an error if the django.contrib.sites is not added to the project.

ERROR: test_urls (newsletter.tests.test_web.WebUserSubscribeTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/sindresorhus/Dropbox/Job/django_sandbox/newsletter/tests/test_web.py", line 171, in setUp
    self.n.site = get_default_sites()
  File "/Users/sindresorhus/Dropbox/Job/django_sandbox/newsletter/models.py", line 30, in get_default_sites
    return [site.id for site in Site.objects.all()]
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/query.py", line 107, in _result_iter
    self._fill_cache()
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/query.py", line 772, in _fill_cache
    self._result_cache.append(self._iter.next())
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/query.py", line 273, in iterator
    for row in compiler.results_iter():
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 680, in results_iter
    for rows in self.execute_sql(MULTI):
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 735, in execute_sql
    cursor.execute(sql, params)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/backends/sqlite3/base.py", line 234, in execute
    return Database.Cursor.execute(self, query, params)
DatabaseError: no such table: django_site

In my opinion "sites" should be optional, and the code should check for the existence for "sites" instead of assuming it's there.

Send Newsletter by Group

I have an application that groups users by 5 groups.
We need to target users by group for certain newsletters.

Thanks

Need a way to bypass email confirmation

In the app I'm writing, emails are not supposed to be confirmed, they should just be added straight onto the list.

If this is already possible: How?

If it's not: how should it be implemented? I'll work on it and create a pull request when it's ready.

I see theres a confirm=True argument passed to some views but that just seems to be for reusing code between /subscribe/ and /subscribe/confirm/.

Two ways this can be implemented:

  • A NEWSLETTER_CONFIRM_EMAIL = False setting (True by default) that bypasses the entire email confirmation process on creation. This is, imho, the more appropriate solution.
  • The ability to pass {"confirm_email": False} argument to the subscribe view in urls.py. This would then be overwritable by the user.

Thoughts?

Improve error reporting when subscribing to a newsletter

One of my client's sites runs SES in production to send emails. It's using ConsoleBackend in debug mode.

If, for any reason, SES cannot send the subscription email (servers busy, bad API key, address not verified...), django-newsletter displays an error page. However, the error is not reported through Django's error report system.

This is bad; either django-newsletter should let django handle the error (and display a generic 500 page; i'd recommend doing it this way) or it should report the error itself somehow.

sorl requires PIL or imagemagick

Sorl requires PIL or imagemagick but doesn't by default pull one of them in as a dependency. I used PIL. Perhaps you could add PIL to requirements.txt or add a comment to the install instructions.

manage.py test fail

Running "manage.py test" results in traceback as shown below:

ERROR: test_detail (newsletter.tests.test_web.AnonymousNewsletterListTestCase)

Traceback (most recent call last):
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/newsletter/tests/test_web.py", line 113, in test_detail
response = self.client.get(detail_url)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/test/client.py", line 439, in get
response = super(Client, self).get(path, data=data, **extra)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/test/client.py", line 244, in get
return self.request(**r)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 150, in get_response
response = callback(request, *_param_dict)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/utils/decorators.py", line 91, in _wrapped_view
response = view_func(request, *args, *_kwargs)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/views/defaults.py", line 20, in page_not_found
t = loader.get_template(template_name) # You need to create a 404.html template.
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/template/loader.py", line 145, in get_template
template, origin = find_template(template_name)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/template/loader.py", line 138, in find_template
raise TemplateDoesNotExist(name)
TemplateDoesNotExist: 404.html

ERROR: test_archive_invisible (newsletter.tests.test_web.ArchiveTestcase)

Test whether an invisible newsletter is indeed not shown.

Traceback (most recent call last):
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/newsletter/tests/test_web.py", line 804, in test_archive_invisible
response = self.client.get(archive_url)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/test/client.py", line 439, in get
response = super(Client, self).get(path, data=data, **extra)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/test/client.py", line 244, in get
return self.request(**r)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 150, in get_response
response = callback(request, *_param_dict)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/utils/decorators.py", line 91, in _wrapped_view
response = view_func(request, *args, *_kwargs)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/views/defaults.py", line 20, in page_not_found
t = loader.get_template(template_name) # You need to create a 404.html template.
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/template/loader.py", line 145, in get_template
template, origin = find_template(template_name)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/template/loader.py", line 138, in find_template
raise TemplateDoesNotExist(name)
TemplateDoesNotExist: 404.html

ERROR: test_archive_unpublished_detail (newsletter.tests.test_web.ArchiveTestcase)

Assert that an unpublished submission is truly inaccessible.

Traceback (most recent call last):
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/newsletter/tests/test_web.py", line 848, in test_archive_unpublished_detail
response = self.client.get(detail_url)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/test/client.py", line 439, in get
response = super(Client, self).get(path, data=data, **extra)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/test/client.py", line 244, in get
return self.request(**r)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 150, in get_response
response = callback(request, *_param_dict)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/utils/decorators.py", line 91, in _wrapped_view
response = view_func(request, *args, *_kwargs)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/views/defaults.py", line 20, in page_not_found
t = loader.get_template(template_name) # You need to create a 404.html template.
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/template/loader.py", line 145, in get_template
template, origin = find_template(template_name)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/template/loader.py", line 138, in find_template
raise TemplateDoesNotExist(name)
TemplateDoesNotExist: 404.html

ERROR: test_list (newsletter.tests.test_web.NoNewsLetterListTestCase)

Test whether all newsletters are in the list and whether the links

Traceback (most recent call last):
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/newsletter/tests/test_web.py", line 35, in test_list
response = self.client.get(self.list_url)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/test/client.py", line 439, in get
response = super(Client, self).get(path, data=data, **extra)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/test/client.py", line 244, in get
return self.request(**r)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 150, in get_response
response = callback(request, *_param_dict)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/utils/decorators.py", line 91, in _wrapped_view
response = view_func(request, *args, *_kwargs)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/views/defaults.py", line 20, in page_not_found
t = loader.get_template(template_name) # You need to create a 404.html template.
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/template/loader.py", line 145, in get_template
template, origin = find_template(template_name)
File "/home/iain/newsletter/dokterbob/local/lib/python2.7/site-packages/django/template/loader.py", line 138, in find_template
raise TemplateDoesNotExist(name)
TemplateDoesNotExist: 404.html


Ran 490 tests in 53.238s

FAILED (errors=4, skipped=1)
Destroying test database for alias 'default'...

2 tests failed - double un/subscription

Having completed all the setup steps, running python manage.py test yields these two errors:

FAIL: test_subscribe_twice (newsletter.tests.test_web.WebUserSubscribeTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/newsletter/tests/test_web.py", line 261, in test_subscribe_twice
    self.assertNotContains(r, 'action="%s"' % self.subscribe_confirm_url)
  File "/usr/lib/python2.7/dist-packages/django/test/testcases.py", line 447, in assertNotContains
    msg_prefix + "Response should not contain '%s'" % text)
AssertionError: Response should not contain 'action="/newsletter/test-newsletter/subscribe/confirm/"'

======================================================================
FAIL: test_unsubscribe_twice (newsletter.tests.test_web.WebUserSubscribeTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/newsletter/tests/test_web.py", line 321, in test_unsubscribe_twice
    self.assertNotContains(r, 'action="%s"' % self.unsubscribe_confirm_url)
  File "/usr/lib/python2.7/dist-packages/django/test/testcases.py", line 447, in assertNotContains
    msg_prefix + "Response should not contain '%s'" % text)
AssertionError: Response should not contain 'action="/newsletter/test-newsletter/unsubscribe/confirm/"'

Proper substitution in logging

When logging using logger.level(msg, substitution_args) rather than logger.level(msg % substitution_args) log messages can be grouped in awesome tools like Sentry. For using this on a production scale this turns out to be a must.

Also, currently, failing messages during submission are not properly logged.

AssertionError: 404 != 200 Erorr in Django 1.5c1 version

Dear,
I am new in python and django world. I need your help.

Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/django_extensions/tests/uuid_field.py", line 48, in testUUIDField_pkAgregateCreate
j = TestAgregateModel.objects.create(a=6)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py", line 149, in create
return self.get_query_set().create(*_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 402, in create
obj.save(force_insert=True, using=self.db)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 537, in save
force_update=force_update, update_fields=update_fields)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 641, in save_base
result = manager._insert([self], fields=fields, return_id=update_pk, using=using, raw=raw)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/manager.py", line 215, in _insert
return insert_query(self.model, objs, fields, *_kwargs)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 1661, in insert_query
return query.get_compiler(using=using).execute_sql(return_id)
File "/usr/local/lib/python2.7/dist-packages/django/db/models/sql/compiler.py", line 937, in execute_sql
cursor.execute(sql, params)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/mysql/base.py", line 122, in execute
six.reraise(utils.IntegrityError, utils.IntegrityError(*tuple(e.args)), sys.exc_info()[2])
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/mysql/base.py", line 120, in execute
return self.cursor.execute(query, args)
File "/usr/lib/python2.7/dist-packages/MySQLdb/cursors.py", line 174, in execute
self.errorhandler(self, exc, value)
File "/usr/lib/python2.7/dist-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
raise errorclass, errorvalue
IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails (test_django_pydream.tests_testagregatemodel, CONSTRAINT testmodel_pk_ptr_id_refs_uuid_field_4c518bbb FOREIGN KEY (testmodel_pk_ptr_id) REFERENCES tests_testmodel_pk (uuid_field))')

FAIL: test_archive_detail (newsletter.tests.test_web.ArchiveTestcase)

Test Submission detail view.

Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/newsletter/tests/test_web.py", line 1034, in test_archive_detail
self.assertEqual(response.status_code, 200)
AssertionError: 404 != 200


Ran 555 tests in 45.847s

FAILED (failures=1, errors=1, skipped=1, expected failures=1)
Destroying test database for alias 'default'...

Could you tell me please, How can I solve this problem?

Thank You
Imran

Catch smtplib.SMTPRecipientsRefused w. form feedback

See: #77 (comment)

Currently, all exceptions in transactional emails (activation, unsubscribe, update etc.) are caught and logged. Furthermore, an error sets the error context variable to true.

Ideally, we would simply catch SMTP-specific errors and make them result in the form not being valid (hence sending the email from the Form.save() functions). This makes it a lot harder to make mistakes in editing the templates, you simply display form errors like you would normally.

Furthermore, we should let all other errors to simply pass through and cause a 500, since this results in unpredictable behaviour.

Integration of delivery feedback in admin

Some service (ie. SendGrid) allow for the retrieval of bounce feedback through their API.

Perhaps we should define some basic model for integrating delivery feedback in the subscription system, so wrong e-mail addresses and automated unsubscriptions are automatically detected. Next we implement a generic listener and connect this to callback views from the mail submission service.

One other option is simply integrating this into the admin on the client site using jQuery and JSON.

Variable `current_site` never exists in template context

Templates like subscription_update.html make use of a variable which should carry the current Site but this variable is never passed on to the templates:

templates/newsletter/subscription_update.html:

<p>{% trans "If the error persists, please don't hesitate to contact us at 
the following email address:" %} 
<a href="mailto:info@{{ current_site.domain }}">
info@{{ current_site.domain }}</a></p

views.py:

env = {
    'newsletter': my_newsletter,
    'form': form,
    'error': error,
    'action': 'update'
}

return render_to_response(
    "newsletter/subscription_update.html",
    env, context_instance=RequestContext(request))

Confusing links in Admin

There are too many confusing links to different kind of objects in the list view.
How exactly should we change this?

Drop Django 1.3 support

Django 1.5 is out, making 1.4 the latest supported branch.

We don't want people running instances of unsupported Django releases and/or forever maintain legacy code. Hence all 1.3 compatibility stuff should be removed.

Invalid block tag 'endthumbnail'

Hi I get an error msg: Invalid block tag: 'endthumbnail', expected 'empty' or 'endfor' while running th runjob. I've install all the requirements.

Any ideas what could be causing? Any help would be appreciated.

Thanks

Add X-Frame exempt for newsletter preview

When Django's clickjacking is enabled, previews don't display.

This can be solved by wrapping the view in xframe_options_exempt. To allow this to work in older Django-versions too, a dynamic import should be used, falling back to a no-op decorator when the exempt is not available.

Tag version working on Django 1.4.5

Hi,

I've tried to install Django-Newsletter in Django 1.4.5 with no luck I can't make it send e-mails.

There is some Tag version that I should install to work in 1.4.5?

The command "./manage.py runjob submit" should send the e-mails right away or will send them to the queue and wait for the crontab to send them?

Best Regards,

Consider django-editor for text editor support

Evgeny Demchenko was kind enough to factor out the pluggable text editor functionality from django-newsletter into django-editor. The idea is to have a common place for pluggable text editor functionality.

Note: currently, django-editor does not allow for pluggable settings. As soon as this in we're ready to add this functionality.

duplicated subscriptions if first one has not yet been subscribed

Here we check if subscribtion exists and it is subscribed. But if it isn't subscribed another subscription will be created.
I think this will help:


if subscription.subscribed:
    raise ValidationError(_("Your e-mail address has already been subscribed to."))
else:
    self.instance = subscription   

Django 1.5 support

Implies at least rewriting the views to use CBV and optionally a pluggable user model.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.