Another Step in the Quest to clean up the code base.
This commit is contained in:
@@ -20,7 +20,6 @@ STATUS_CHOICES = (
|
||||
)
|
||||
|
||||
|
||||
|
||||
class OverwriteStorage(FileSystemStorage):
|
||||
"""
|
||||
Returns same name for existing file and deletes existing file on save.
|
||||
@@ -31,5 +30,5 @@ class OverwriteStorage(FileSystemStorage):
|
||||
self.delete(name)
|
||||
return super(OverwriteStorage, self)._save(name, content)
|
||||
|
||||
def get_available_name(self, name):
|
||||
def get_available_name(self, name, max_length=None):
|
||||
return name
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
"""A list of all approved countries on planet earth, i18n enabled."""
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
COUNTRIES = (
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: kasu.utils\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-05-10 23:16+0200\n"
|
||||
"POT-Creation-Date: 2017-06-19 22:46+0200\n"
|
||||
"PO-Revision-Date: 2016-09-28 00:24+0200\n"
|
||||
"Last-Translator: Christian Berg <xeniac@posteo.at>\n"
|
||||
"Language-Team: Kasu <verein@kasu.at>\n"
|
||||
@@ -18,15 +18,15 @@ msgstr ""
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Poedit 1.8.9\n"
|
||||
|
||||
#: utils/__init__.py:16
|
||||
#: utils/__init__.py:17
|
||||
msgid "Rejected"
|
||||
msgstr "Zurückgewiesen"
|
||||
|
||||
#: utils/__init__.py:17
|
||||
#: utils/__init__.py:18
|
||||
msgid "Waiting..."
|
||||
msgstr "Wartend..."
|
||||
|
||||
#: utils/__init__.py:18
|
||||
#: utils/__init__.py:19
|
||||
msgid "Published"
|
||||
msgstr "Veröffentlicht"
|
||||
|
||||
@@ -1014,53 +1014,44 @@ msgstr "Sambia"
|
||||
msgid "Zimbabwe"
|
||||
msgstr "Zimbabwe"
|
||||
|
||||
#: utils/html5/forms.py:48
|
||||
msgid ""
|
||||
"Select a valid choice. That choice is not one of the available "
|
||||
"choices."
|
||||
msgstr ""
|
||||
"Bitte eine gültige Auswahl treffen. Diese Option steht nicht zur Verfügung."
|
||||
#~ msgid ""
|
||||
#~ "Select a valid choice. That choice is not one of the available "
|
||||
#~ "choices."
|
||||
#~ msgstr ""
|
||||
#~ "Bitte eine gültige Auswahl treffen. Diese Option steht nicht zur "
|
||||
#~ "Verfügung."
|
||||
|
||||
#: utils/html5/forms.py:94
|
||||
msgid ""
|
||||
"Select a valid choice. That choice is not one of the available "
|
||||
"choices."
|
||||
msgstr ""
|
||||
"Bitte eine gültige Auswahl treffen. Diese Option steht nicht zur Verfügung."
|
||||
#~ msgid ""
|
||||
#~ "Select a valid choice. That choice is not one of the available "
|
||||
#~ "choices."
|
||||
#~ msgstr ""
|
||||
#~ "Bitte eine gültige Auswahl treffen. Diese Option steht nicht zur "
|
||||
#~ "Verfügung."
|
||||
|
||||
#: utils/html5/forms.py:132
|
||||
msgid "yyyy-mm-dd"
|
||||
msgstr "tt.mm.jjjj"
|
||||
#~ msgid "yyyy-mm-dd"
|
||||
#~ msgstr "tt.mm.jjjj"
|
||||
|
||||
#: utils/html5/forms.py:238
|
||||
msgid "Only humans are allowed to submit this form."
|
||||
msgstr "Nur Menschen dürfen dieses Formular übermitteln."
|
||||
#~ msgid "Only humans are allowed to submit this form."
|
||||
#~ msgstr "Nur Menschen dürfen dieses Formular übermitteln."
|
||||
|
||||
#: utils/management/commands/compresscss.py:22
|
||||
#: utils/management/commands/compressjs.py:21
|
||||
msgid "Reads raw CSS from stdin, and writes compressed CSS to stdout."
|
||||
msgstr "Lese das CSS von stdin, und gebe es in komprimierter Form wieder aus."
|
||||
#~ msgid "Reads raw CSS from stdin, and writes compressed CSS to stdout."
|
||||
#~ msgstr ""
|
||||
#~ "Lese das CSS von stdin, und gebe es in komprimierter Form wieder aus."
|
||||
|
||||
#: utils/management/commands/scss-compiler.py:20
|
||||
msgid "Compile SCSS rules."
|
||||
msgstr "kompiliere SCSS Regeln."
|
||||
#~ msgid "Compile SCSS rules."
|
||||
#~ msgstr "kompiliere SCSS Regeln."
|
||||
|
||||
#: utils/management/commands/scss-compiler.py:29
|
||||
#, python-format
|
||||
msgid "Compressing CSS for %s"
|
||||
msgstr "Komprimiere CSS für %s"
|
||||
#~ msgid "Compressing CSS for %s"
|
||||
#~ msgstr "Komprimiere CSS für %s"
|
||||
|
||||
#: utils/mixins.py:28
|
||||
msgid "You need to be logged in"
|
||||
msgstr "Eine Anmeldung ist erforderlich"
|
||||
#~ msgid "You need to be logged in"
|
||||
#~ msgstr "Eine Anmeldung ist erforderlich"
|
||||
|
||||
#: utils/mixins.py:60
|
||||
msgid "You don't have the permission to do this"
|
||||
msgstr "Du hast nicht genügend Rechte dafür."
|
||||
#~ msgid "You don't have the permission to do this"
|
||||
#~ msgstr "Du hast nicht genügend Rechte dafür."
|
||||
|
||||
#: utils/mixins.py:100
|
||||
msgid "You don't have the permissions for this"
|
||||
msgstr "Du hast nicht genügend Rechte dafür."
|
||||
#~ msgid "You don't have the permissions for this"
|
||||
#~ msgstr "Du hast nicht genügend Rechte dafür."
|
||||
|
||||
#~ msgid "Compressing JavaScript for %s"
|
||||
#~ msgstr "Komprimiere JavaScript für %s"
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
import logging
|
||||
"""
|
||||
MassMailer can send E-Mails via an SMTP Connection to multiple recipients.
|
||||
|
||||
from django.core import mail
|
||||
Each E-Mail will be send individually and can be personalized. It will be send
|
||||
as HTML and Plain-Text Message.
|
||||
"""
|
||||
import logging
|
||||
import smtplib
|
||||
|
||||
import django.core.mail
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.sites.models import Site
|
||||
from django.template import loader
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
LOGGER = logging.getLogger('maillog')
|
||||
|
||||
|
||||
class MassMailer(object):
|
||||
@@ -12,64 +21,39 @@ class MassMailer(object):
|
||||
Each E-Mail will be send individually and can be personalized.
|
||||
It will be send as HTML and Plain-Text Message.
|
||||
"""
|
||||
context = {}
|
||||
headers = {}
|
||||
subject = None
|
||||
txt_template = None
|
||||
html_template = None
|
||||
|
||||
def __init__(self, subject=None, template=None, context=None):
|
||||
self.USER_MODEL = get_user_model()
|
||||
self.mail_queue = set()
|
||||
self.recipients = set()
|
||||
self.subject = subject
|
||||
self.template = 'email'
|
||||
def __init__(self, subject=None, context=None, txt_template=None,
|
||||
html_template=None):
|
||||
"""set the subject and context for further processing."""
|
||||
self.context = context
|
||||
self.log = logging.getLogger('maillog')
|
||||
|
||||
def open_smtp_connection(self):
|
||||
try:
|
||||
self.smtp_connection = mail.get_connection(fail_silently=False)
|
||||
self.smtp_connection.open()
|
||||
self.mail_counter = 0
|
||||
except:
|
||||
self.log.error('Connection to SMTP server failed. Giving up!')
|
||||
raise False
|
||||
self.context['site'] = Site.objects.get_current()
|
||||
self.headers = {}
|
||||
self.subject = subject
|
||||
self.txt_template = loader.get_template(txt_template)
|
||||
if html_template:
|
||||
self.html_template = loader.get_template(html_template)
|
||||
else:
|
||||
self.log.debug('Connected to SMTP server.')
|
||||
return True
|
||||
self.html_template = None
|
||||
|
||||
def close_smtp_connection(self):
|
||||
self.smtp_connection.close()
|
||||
self.log.debug("closed the SMTP connection. I'm done")
|
||||
def process_mails(self, recipients):
|
||||
""" Generate personalised e-mails for each user in the recipients list.
|
||||
|
||||
def add_recipient(self, recipient):
|
||||
if isinstance(recipient, self.USER_MODEL):
|
||||
self.recipients.add(recipient)
|
||||
else:
|
||||
self.log.warning('%s is not a User Object!', recipient)
|
||||
|
||||
def add_recipients(self, user_list):
|
||||
for user in user_list:
|
||||
if isinstance(user, self.USER_MODEL):
|
||||
self.log.debug('Adding %s as Recipient' % user)
|
||||
self.recipients.add(user)
|
||||
else:
|
||||
self.log.warning('%s is not a User Object!', user)
|
||||
|
||||
def process_mails(self):
|
||||
:param recipients: A iterateable of User objects that shoud get the mail
|
||||
:return: a iteratable of Mail Objects that should read for sending.
|
||||
"""
|
||||
mail_context = self.context
|
||||
mail_context['site'] = Site.objects.get_current()
|
||||
|
||||
self.txt_template = loader.get_template(self.txt_template)
|
||||
if self.html_template:
|
||||
self.html_template = loader.get_template(self.html_template)
|
||||
|
||||
for recipient in self.recipients:
|
||||
mail_queue = set()
|
||||
for recipient in recipients:
|
||||
if isinstance(recipient, get_user_model()):
|
||||
LOGGER.debug('Adding %s as Recipient' % recipient)
|
||||
else:
|
||||
LOGGER.warning('%s is not a User Object!', recipient)
|
||||
continue
|
||||
mail_context['recipient'] = recipient
|
||||
mail_to = "%s %s <%s>" % (recipient.first_name,
|
||||
recipient.last_name, recipient.email)
|
||||
message = mail.EmailMultiAlternatives(
|
||||
print(recipient.__dict__)
|
||||
mail_to = "{first_name!s} {last_name!s} <{email!s}>".format(
|
||||
**recipient.__dict__)
|
||||
message = django.core.mail.EmailMultiAlternatives(
|
||||
subject=self.subject,
|
||||
body=self.txt_template.render(mail_context),
|
||||
to=(mail_to,),
|
||||
@@ -79,30 +63,38 @@ class MassMailer(object):
|
||||
message.attach_alternative(
|
||||
self.html_template.render(mail_context), "text/html"
|
||||
)
|
||||
self.mail_queue.add(message)
|
||||
mail_queue.add(message)
|
||||
return mail_queue
|
||||
|
||||
def set_header(self, name, value):
|
||||
"""Add or modify an E-Mail Header to the Messages
|
||||
|
||||
:param name: The Header Name that should be added
|
||||
:param value: THe Header Value that shoud be added or set
|
||||
"""
|
||||
self.headers[name] = value
|
||||
|
||||
def send(self):
|
||||
def send(self, recipients=set()):
|
||||
"""
|
||||
Process the E-Mails and send them
|
||||
|
||||
:param recipients: list of Users that should receive this Mail
|
||||
:return:
|
||||
"""
|
||||
self.process_mails()
|
||||
if len(self.mail_queue) == 0:
|
||||
self.log.info('No recipients for eMail "%s", bye!', self.subject)
|
||||
mail_queue = self.process_mails(recipients)
|
||||
if len(mail_queue) == 0:
|
||||
LOGGER.info('No recipients for eMail "%s", bye!', self.subject)
|
||||
return True
|
||||
else:
|
||||
self.log.info('Sending eMail "%s" to %d people', self.subject,
|
||||
len(self.mail_queue))
|
||||
self.log.debug(self.recipients)
|
||||
LOGGER.info('Sending eMail "%s" to %d people', self.subject,
|
||||
len(mail_queue))
|
||||
LOGGER.debug(recipients)
|
||||
|
||||
self.open_smtp_connection()
|
||||
for mail in self.mail_queue:
|
||||
try:
|
||||
mail.send()
|
||||
except:
|
||||
self.log.warning("Mail failed for: %s", mail.to)
|
||||
else:
|
||||
self.log.info("Mail sent successful to: %s" % mail.to)
|
||||
self.close_smtp_connection()
|
||||
with django.core.mail.get_connection(fail_silently=False) as connection:
|
||||
for mail in mail_queue:
|
||||
try:
|
||||
mail.connection = connection
|
||||
mail.send()
|
||||
except smtplib.SMTPException:
|
||||
LOGGER.warning("Mail failed for: %s", mail.to)
|
||||
else:
|
||||
LOGGER.info("Mail sent successful to: %s" % mail.to)
|
||||
|
||||
@@ -1,20 +1,33 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on 23.05.2011
|
||||
|
||||
@author: christian
|
||||
"""
|
||||
"""This Middleware compresses the HTML Output at the End. It strips the Spaces
|
||||
between Tags, an at the beginning and the end of the content."""
|
||||
from django.utils.html import strip_spaces_between_tags
|
||||
|
||||
|
||||
class CompressHtmlMiddleware(object):
|
||||
"""
|
||||
This Middleware compresses the HTML Output at the End. It strips the Spaces
|
||||
between Tags, an at the beginning and the end of the content.
|
||||
"""
|
||||
"""This Middleware compresses strips the spaces between tags, and at the
|
||||
beginning and the end of the content."""
|
||||
# TODO: Port to django 1.10 and upward
|
||||
|
||||
def process_response(self, request, response):
|
||||
def __init__(self, get_response):
|
||||
"""
|
||||
|
||||
:param get_response:
|
||||
"""
|
||||
self.get_response = get_response
|
||||
regex = ">[\s]*<"
|
||||
|
||||
def __call__(self, request):
|
||||
"""
|
||||
|
||||
:param request:
|
||||
:return:
|
||||
"""
|
||||
|
||||
# Code to be executed for each request before
|
||||
# the view (and later middleware) are called.
|
||||
|
||||
response = self.get_response(request)
|
||||
if 'text/html' in response['Content-Type']:
|
||||
response.content = strip_spaces_between_tags(response.content)
|
||||
response.content = response.content.strip()
|
||||
response.content = strip_spaces_between_tags(
|
||||
response.content).strip()
|
||||
return response
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth import REDIRECT_FIELD_NAME
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django import http
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.http import urlquote
|
||||
|
||||
|
||||
class LoginRequiredMixin(object):
|
||||
"""
|
||||
View mixin which verifies that the user has authenticated.
|
||||
|
||||
NOTE:
|
||||
This should be the left-most mixin of a view.
|
||||
"""
|
||||
login_url = settings.LOGIN_URL
|
||||
raise_exception = False
|
||||
redirect_field_name = REDIRECT_FIELD_NAME
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if request.user.is_authenticated():
|
||||
return super(LoginRequiredMixin, self).dispatch(request, *args,
|
||||
**kwargs)
|
||||
elif self.raise_exception: # if an exception was desired
|
||||
return http.HttpResponseForbidden() # return a forbidden response.
|
||||
else:
|
||||
messages.error(request, _("You need to be logged in"))
|
||||
path = urlquote(request.get_full_path())
|
||||
return http.HttpResponseRedirect(
|
||||
"%s?%s=%s" % (self.login_url, self.redirect_field_name, path))
|
||||
|
||||
|
||||
class PermissionRequiredMixin(object):
|
||||
"""
|
||||
View mixin which verifies that the loggedin user has the specified
|
||||
permission.
|
||||
|
||||
Class Settings
|
||||
`permission_required` - the permission to check for.
|
||||
`login_url` - the login url of site
|
||||
`redirect_field_name` - defaults to "next"
|
||||
`raise_exception` - defaults to False - raise 403 if set to True
|
||||
|
||||
Example Usage
|
||||
|
||||
class SomeView(PermissionRequiredMixin, ListView):
|
||||
...
|
||||
# required
|
||||
permission_required = "app.permission"
|
||||
|
||||
# optional
|
||||
login_url = "/signup/"
|
||||
redirect_field_name = "hollaback"
|
||||
raise_exception = True
|
||||
...
|
||||
"""
|
||||
login_url = settings.LOGIN_URL
|
||||
permission_required = None
|
||||
permission_failed_message = _("You don't have the permission to do this")
|
||||
raise_exception = False
|
||||
redirect_field_name = REDIRECT_FIELD_NAME
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
# Verify class settings
|
||||
if self.permission_required is None or len(
|
||||
self.permission_required.split(".")) != 2:
|
||||
raise ImproperlyConfigured(
|
||||
"'PermissionRequiredMixin' requires 'permission_required' attribute to be set.")
|
||||
has_permission = request.user.has_perm(self.permission_required)
|
||||
|
||||
if has_permission:
|
||||
return super(PermissionRequiredMixin, self).dispatch(request, *args,
|
||||
**kwargs)
|
||||
elif self.raise_exception:
|
||||
return http.HttpResponseForbidden()
|
||||
else:
|
||||
messages.warning(request, self.permission_failed_message)
|
||||
path = urlquote(request.get_full_path())
|
||||
return http.HttpResponseRedirect(
|
||||
"%s?%s=%s" % (self.login_url, self.redirect_field_name, path))
|
||||
|
||||
|
||||
class SuperuserRequiredMixin(object):
|
||||
"""
|
||||
Mixin allows you to require a user with `is_superuser` set to True.
|
||||
"""
|
||||
login_url = settings.LOGIN_URL # LOGIN_URL from project settings
|
||||
raise_exception = False # Default whether to raise an exception to none
|
||||
redirect_field_name = REDIRECT_FIELD_NAME # Set by django.contrib.auth
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if request.user.is_superuser: # If the user is a standard user,
|
||||
return super(SuperuserRequiredMixin, self).dispatch(request, *args,
|
||||
**kwargs)
|
||||
elif self.raise_exception: # *and* if an exception was desired
|
||||
return http.HttpResponseForbidden() # return a forbidden response.
|
||||
else:
|
||||
messages.error(request,
|
||||
_("You don't have the permissions for this"))
|
||||
path = urlquote(request.get_full_path())
|
||||
return http.HttpResponseRedirect(
|
||||
"%s?%s=%s" % (self.login_url, self.redirect_field_name, path))
|
||||
@@ -1,8 +1,18 @@
|
||||
""" This should be the place to test the functinality of the random
|
||||
stuff that has been collected in the utils package. Idealy we shuld get rid
|
||||
of this random addons. """
|
||||
|
||||
import unittest
|
||||
import html_cleaner
|
||||
from utils import html_cleaner
|
||||
|
||||
|
||||
class HtmlTestCase(unittest.TestCase):
|
||||
""" Unit testcase to verify the HTML cleanup class.
|
||||
|
||||
It should removed unwanted syling tags an more get rid of dangerous
|
||||
JavaScript elements.
|
||||
"""
|
||||
|
||||
known_html = (
|
||||
('<STRONG>Fett!</STRONG>', '<strong>Fett!</strong>'),
|
||||
('<a href="link.html" onclick="do_evil()">Bad Link</a>',
|
||||
@@ -34,7 +44,7 @@ class HtmlTestCase(unittest.TestCase):
|
||||
xxx-xxxx</FONT></DIV></BODY></HTML>
|
||||
''',
|
||||
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">'
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
def test_html_cleaner(self):
|
||||
|
||||
Reference in New Issue
Block a user