Anpassungen des Codes an Django 1.11 mit Python 3

Grapelli wurde entfernt, das neue Django Admin ist hübsch genug.
This commit is contained in:
2017-05-10 10:15:39 +02:00
parent 5437b7b8de
commit 321531c160
25 changed files with 219 additions and 121 deletions

View File

@@ -1,10 +1,9 @@
# -*- encoding: utf-8 -*-
from django.conf.urls import patterns, url
from django.conf.urls import url
from .views import *
urlpatterns = patterns(
'',
urlpatterns = [
url(r'^$', EventGallery.as_view(), name='event-gallery'),
url(r'^(?P<event>[\d]+)/$', EventPhotoList.as_view(),
name='event-photo-list'),
@@ -15,4 +14,4 @@ urlpatterns = patterns(
url(r'^delete/(?P<pk>[\d]+)/$', DeleteEventPhoto.as_view(),
name='delete-event-photo'),
url(r'^upload/$', EventPhotoUpload.as_view(), name='event-photo-upload'),
)
]

View File

@@ -135,7 +135,7 @@ class Event(models.Model):
verbose_name_plural = _('Events')
ordering = ('start', 'end',)
def __unicode__(self):
def __str__(self):
try:
return "%(name)s (%(date)s)" % {'name': self.name,
'date': self.start.date()}
@@ -235,7 +235,7 @@ class Location(models.Model):
verbose_name = _('Venue')
verbose_name_plural = _('Venues')
def __unicode__(self):
def __str__(self):
return self.name
@property
@@ -306,7 +306,7 @@ class Photo(models.Model):
verbose_name = _('Event Image')
verbose_name_plural = _('Event Images')
def __unicode__(self):
def __str__(self):
return os.path.basename(self.image.name)
def rotate(self, rotate):

View File

@@ -1,10 +1,9 @@
# -*- encoding: utf-8 -*-
from django.conf.urls import patterns, url
from django.conf.urls import url
from django.views.generic import RedirectView
from .views import *
urlpatterns = patterns(
'',
urlpatterns = [
url(r'^$', RedirectView.as_view(url='/events/upcoming/', permanent=True)),
url(r'^(?P<year>[\d]{4})/$', EventArchiveYear.as_view(),
name='event-archive'),
@@ -19,4 +18,4 @@ urlpatterns = patterns(
url(r'^add/$', EventForm.as_view(), name='event-form'),
url(r'^archive/$', EventArchiveIndex.as_view(), name='event-archive'),
url(r'^upcoming/$', UpcomingEvents.as_view(), name='upcoming-events'),
)
]

View File

@@ -29,7 +29,6 @@ STATICFILES_FINDERS = (
# Apps
PREREQ_APPS = [
'grappelli',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
@@ -84,20 +83,20 @@ TEMPLATES = [
'DIRS': [path.join(PROJECT_PATH, 'templates/')],
'OPTIONS': {
'context_processors': [
'content.context_processors.content_menus',
'django.contrib.auth.context_processors.auth',
'django.template.context_processors.csrf',
'django.template.context_processors.debug',
'django.template.context_processors.i18n',
'django.template.context_processors.media',
'django.template.context_processors.request',
'django.template.context_processors.static',
'django.template.context_processors.tz',
'django.contrib.messages.context_processors.messages',
'django.core.context_processors.csrf',
'django.core.context_processors.request',
'django.contrib.messages.context_processors.messages',
'content.context_processors.content_menus',
'events.context_processors.upcoming_events',
'social.apps.django_app.context_processors.backends',
'social.apps.django_app.context_processors.login_redirect',
'social_django.context_processors.backends',
'social_django.context_processors.login_redirect'
],
'loaders': [
('django.template.loaders.cached.Loader', [
@@ -111,8 +110,8 @@ TEMPLATES = [
#Settings for Security Middleware
CSP_DEFAULT_SRC = ("'self'",)
CSP_IMG_SRC = CSP_DEFAULT_SRC
CSP_SCRIPT_SRC = ("'self'", "'unsafe-inline'")
CSP_IMG_SRC = ("'self'", "'unsafe-eval'")
CSP_SCRIPT_SRC = ("'self'", "'unsafe-inline'", "'unsafe-eval'")
CSP_STYLE_SRC = ("'self'", "'unsafe-inline'")
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True

View File

@@ -1,6 +1,6 @@
# -*- encoding: utf-8 -*-
from django.conf import settings
from django.conf.urls import patterns, include, url
from django.conf.urls import include, url
from django.contrib import admin
from django.contrib.sitemaps.views import sitemap
from django.views.generic.base import TemplateView
@@ -20,8 +20,7 @@ sitemaps = {
'pages': PageSitemap,
}
urlpatterns = patterns(
'',
urlpatterns = [
url(r'^$', StartPage.as_view()),
url(r'^404/$', TemplateView.as_view(template_name='404.html')),
url(r'^add_page/(?P<path>[\+\.\-\d\w\/]+)/$', PageAddForm.as_view(), name='add-page'),
@@ -37,7 +36,6 @@ urlpatterns = patterns(
url(r'^feeds/comments/$', LatestComments(), name='feed-latest-comments'),
url(r'^gallery/', include('events.gallery_urls')),
url(r'^google25dabc1a49a9ef03.html$', TemplateView.as_view(template_name='google25dabc1a49a9ef03.html')),
url(r'^grappelli/', include('grappelli.urls')),
url(r'^i18n/', include('django.conf.urls.i18n'), name='start-page'),
url(r'^index.html$', StartPage.as_view()),
url(r'^manifest.json$', TemplateView.as_view(template_name='manifest.json')),
@@ -51,7 +49,8 @@ urlpatterns = patterns(
url(r'^users/(?P<username>[\-\.\d\w]+)/$', MembershipDetail.as_view(), name='membership-details'),
url(r'^(?P<path>[\-\d\w\/]+)\.html$', PageHtml.as_view(), name='view-page'),
url(r'^(?P<path>[\-\d\w\/]+)\.pdf$', PagePdf.as_view()),
)
url('', include('social_django.urls', namespace='social'))
]
if settings.DEBUG:
from django.conf.urls.static import static
@@ -59,13 +58,8 @@ if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
if 'rosetta' in settings.INSTALLED_APPS:
urlpatterns += patterns('', url(r'^rosetta/', include('rosetta.urls')),)
urlpatterns += url(r'^rosetta/', include('rosetta.urls'))
if 'debug_toolbar' in settings.INSTALLED_APPS:
import debug_toolbar
urlpatterns += [
url(r'^__debug__/', include(debug_toolbar.urls)),
]
urlpatterns.append(url(r'^__debug__/', include(debug_toolbar.urls)))

View File

@@ -1,7 +1,6 @@
# -*- encoding: utf-8 -*-
from django.utils.log import getLogger
from django.core.cache import cache
import logging
KYU_RANKS = (
(45, 1),
(40, 2),
@@ -30,10 +29,10 @@ DAN_RANKS = (
DAN_RANKS_DICT = dict([(dan, points) for points, dan in DAN_RANKS])
MIN_HANCHANS_FOR_LADDER = 5
logger = getLogger('kasu.mahjong_ranking')
logger = logging.getLogger('kasu.mahjong_ranking')
def set_dirty(event=None, season=None, user=None):
def set_dirty(event=None, season=None, user=None, hanchan_date=None):
if season and user:
key_to_add = (season, user)
queue_name = 'ladder_ranking_queue'
@@ -44,7 +43,7 @@ def set_dirty(event=None, season=None, user=None):
key_to_add = (event, user)
queue_name = 'event_ranking_queue'
elif user:
key_to_add = user
key_to_add = (user, hanchan_date)
queue_name = 'kyu_dan_ranking_queue'
if key_to_add and queue_name:
recalculation_queue = cache.get(queue_name, set())

View File

@@ -24,10 +24,10 @@ class HanchanForm(forms.ModelForm):
class Meta(object):
model = models.Hanchan
fields = ('start',
'player1', 'player1_input_score', # 'player1_comment',
'player2', 'player2_input_score', # 'player2_comment',
'player3', 'player3_input_score', # 'player3_comment',
'player4', 'player4_input_score', # 'player4_comment',
'player1', 'player1_input_score',
'player2', 'player2_input_score',
'player3', 'player3_input_score',
'player4', 'player4_input_score',
'comment')
widgets = {'event': forms.HiddenInput(),
'comment': forms.widgets.Textarea(attrs={'rows': 4, 'cols': 40})
@@ -35,11 +35,14 @@ class HanchanForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(HanchanForm, self).__init__(*args, **kwargs)
# self.fields['event'].widget.attrs['disabled'] = True
for i in xrange(1, 4):
player_queryset = USER_MODEL.objects.filter(is_active=True,
membership=True)
for i in range(1, 4):
player = 'player%d' % i
player_input_score = 'player%d_input_score' % i
self.fields[player_input_score].widget.attrs['size'] = 6
self.fields[player_input_score].widget.attrs['type'] = 'number'
self.fields[player].queryset = player_queryset

View File

@@ -20,6 +20,9 @@ class DenormalizationUpdateMiddleware(object):
def process_response(self, request, response):
# We only do this in POST request, to speedup the responsetime.
if request.method == 'POST':
print('event_ranking_queue', cache.get('event_ranking_queue', set()))
print('kyu_dan_ranking_queue', cache.get('kyu_dan_ranking_queue', set()))
print('ladder_ranking_queue', cache.get('ladder_ranking_queue', set()))
queue = cache.get('event_ranking_queue', set())
if len(queue) > 0:
self.recalculate_event_rankings(queue)
@@ -45,8 +48,6 @@ class DenormalizationUpdateMiddleware(object):
def recalculate_event_rankings(self, queue):
# recalculate tournament (event) rankings:
for event_id, user_id in queue:
logger.info("recalculate %d tournament Ranking in %s",
user_id, event_id)
ranking = models.EventRanking.objects.get_or_create(
event_id=event_id, user_id=user_id)[0]
ranking.recalculate()
@@ -54,10 +55,10 @@ class DenormalizationUpdateMiddleware(object):
return queue
def recalulate_kyu_dan_ranking(self, queue):
for user_id in queue:
ranking = models.KyuDanRanking.objects.get_or_create(user_id=user_id)[
0]
ranking.recalculate()
for user_id, hanchan_start in queue:
ranking = models.KyuDanRanking.objects.get_or_create(
user_id=user_id)[0]
ranking.recalculate(hanchan_start)
return queue
def recalculate_ladder_ranking(self, queue):

View File

@@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mahjong_ranking', '0003_auto_20160916_1800'),
]
operations = [
migrations.AlterField(
model_name='hanchan',
name='comment',
field=models.TextField(verbose_name='Anmerkung', blank=True),
),
migrations.AlterField(
model_name='hanchan',
name='player1_comment',
field=models.CharField(verbose_name='Anmerkung', max_length=255, editable=False, blank=True),
),
migrations.AlterField(
model_name='hanchan',
name='player2_comment',
field=models.CharField(verbose_name='Anmerkung', max_length=255, editable=False, blank=True),
),
migrations.AlterField(
model_name='hanchan',
name='player3_comment',
field=models.CharField(verbose_name='Anmerkung', max_length=255, editable=False, blank=True),
),
migrations.AlterField(
model_name='hanchan',
name='player4_comment',
field=models.CharField(verbose_name='Anmerkung', max_length=255, editable=False, blank=True),
),
]

View File

@@ -79,7 +79,6 @@ class EventRanking(models.Model):
self.save(force_update=True)
class Hanchan(models.Model):
"""
Ein komplette Runde Mahjong, die aus genau 4 Spielern bestehen muss.
@@ -95,7 +94,6 @@ class Hanchan(models.Model):
player1 = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
limit_choices_to={'is_active': True, 'membership': True},
related_name='user_hanchan+',
verbose_name=_('Player 1'))
player1_input_score = models.IntegerField(_('Score'))
@@ -115,7 +113,6 @@ class Hanchan(models.Model):
player2 = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
limit_choices_to={'is_active': True, 'membership': True},
related_name='user_hanchan+',
verbose_name=_('Player 2'))
player2_input_score = models.IntegerField(_('Score'))
@@ -135,7 +132,6 @@ class Hanchan(models.Model):
player3 = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
limit_choices_to={'is_active': True, 'membership': True},
related_name='user_hanchan+',
verbose_name=_('Player 3'))
player3_input_score = models.IntegerField(_('Score'))
@@ -155,7 +151,6 @@ class Hanchan(models.Model):
player4 = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
limit_choices_to={'is_active': True, 'membership': True},
related_name='user_hanchan+',
verbose_name=_('Player 4'))
player4_input_score = models.IntegerField(_('Score'))
@@ -205,11 +200,11 @@ class Hanchan(models.Model):
try:
self.clean_fields()
except ValidationError as e:
print e.update_error_dict(errors)
except ValidationError as exception:
exception.update_error_dict(errors)
return
for i in xrange(1, 5):
for i in range(1, 5):
player = getattr(self, 'player%d' % i)
input_score = getattr(self, 'player%d_input_score' % i)
score_sum += input_score
@@ -309,7 +304,7 @@ class Hanchan(models.Model):
@property
def player_list(self):
player_list = []
for i in xrange(1, 5):
for i in range(1, 5):
player_list.append({
'user': getattr(self, 'player%d' % i),
'input_score': getattr(self, 'player%d_input_score' % i),
@@ -324,10 +319,12 @@ class Hanchan(models.Model):
return sorted(player_list, key=lambda player: player['input_score'],
reverse=True)
def save(self, **kwargs):
def save(self, recalculate=True, **kwargs):
self.season = self.event.mahjong_season or self.start.year
self.full_clean()
if recalculate:
self.compute_player_placements()
update_ranking(sender=Hanchan, instance=self)
return models.Model.save(self, **kwargs)
@@ -435,7 +432,7 @@ class KyuDanRanking(models.Model):
else:
return reverse('player-kyu-score', args=[self.user.username])
def recalculate(self):
def recalculate(self, hanchan_start=None):
"""
Fetches all valid Hanchans from this Player and recalculates his
Kyu/Dan Ranking.
@@ -449,14 +446,23 @@ class KyuDanRanking(models.Model):
self.good_hanchans = 0
self.won_hanchans = 0
logger.info("recalculating Kyu/Dan points for %s...", self.user)
logger.info(
"recalculating Kyu/Dan points for %s since %s...",
self.user, str(hanchan_start)
)
self.update_rank()
valid_hanchans = Hanchan.objects.confirmed_hanchans(user=self.user)
valid_hanchans = valid_hanchans.order_by('start')
if self.legacy_date:
valid_hanchans = valid_hanchans.filter(start__gt=self.legacy_date)
""" TODO: Hanchan Punkte nur neu berechnen wenn sie vor hachan_start
lag. Es müssen aber alle durch die Schleife rennen, damit die Punkte
richtig gezählt werden."""
if hanchan_start:
valid_hanchans = valid_hanchans.filter(start__gte=hanchan_start)
self.hanchan_count += valid_hanchans.count()
for hanchan in valid_hanchans:
logger.debug('Update Kyu/Dan points for Hanchan started on %s', str(hanchan.start))
hanchan.get_playerdata(self.user)
hanchan.bonus_points = 0
hanchan.player_comment = u""
@@ -469,7 +475,7 @@ class KyuDanRanking(models.Model):
self.won_hanchans += 1 if hanchan.placement == 1 else 0
self.good_hanchans += 1 if hanchan.placement == 2 else 0
hanchan.update_playerdata(self.user)
hanchan.save(force_update=True)
hanchan.save(recalculate=False)
self.save(force_update=True)
def update_hanchan_points(self, hanchan):
@@ -537,7 +543,7 @@ class KyuDanRanking(models.Model):
if self.dan_points > min_points:
self.dan = dan_rank
break
if self.dan > old_dan:
if old_dan == None or self.dan > old_dan:
self.wins_in_a_row = 0
elif self.kyu_points < 1:
self.kyu_points = 0
@@ -600,10 +606,16 @@ class SeasonRanking(models.Model):
def update_ranking(sender, instance, **kwargs):
for user in (instance.player1, instance.player2, instance.player3, instance.player4):
logger.debug("marking %s's kyu/dan for recalculation", user)
set_dirty(user=user.id)
logger.debug(
"marking %(user)s's kyu/dan for recalculation since %(start)s",
{'user':user, 'start':str(instance.start.date())}
)
set_dirty(user=user.id, hanchan_date=instance.start.date())
if instance.season:
logger.debug("marking %s's ladder %i season for recalculation.", user, instance.season)
logger.debug(
"marking %s's ladder %i season for recalculation.",
user, instance.season
)
set_dirty(user=user.id, season=instance.season)
logger.debug("marking season %d for recalculation.", instance.season)
set_dirty(season=instance.season)
@@ -611,4 +623,4 @@ def update_ranking(sender, instance, **kwargs):
set_dirty(event=instance.event_id, user=user.id)
models.signals.pre_delete.connect(update_ranking, sender=Hanchan)
models.signals.post_save.connect(update_ranking, sender=Hanchan)
# models.signals.post_save.connect(update_ranking, sender=Hanchan)

View File

@@ -5,14 +5,12 @@ Created on 03.10.2011
@author: christian
"""
from django.conf.urls import * # @UnusedWildImport
from django.views.generic import RedirectView
import views
from django.conf.urls import url
from . import views
urlpatterns = patterns(
'',
urlpatterns = [
url(r'^$', RedirectView.as_view(
url='/ranking/mahjong-ladder/', permanent=True)
),
@@ -42,4 +40,4 @@ urlpatterns = patterns(
name="kyudanranking-list"),
url(r'^mahjong/(?P<order_by>[\+\-\w]+)/$',
views.KyuDanRankingList.as_view(), name="kyudanranking-list"),
)
]

View File

@@ -256,5 +256,4 @@ class PlayerLadderScore(PlayerScore):
self.season = date.today().year
hanchan_list = models.Hanchan.objects.season_hanchans(
user=self.user, season=self.season)
print hanchan_list
return hanchan_list

View File

@@ -4,14 +4,13 @@ Created on 03.10.2011
@author: christian
"""
from django.conf.urls import * # @UnusedWildImport
from django.conf.urls import url
from django.views.generic import RedirectView
from .views import DeleteGame, ListGames, ListPlayerGames, \
ListRankings, GameForm
urlpatterns = patterns(
'maistar_ranking.views',
urlpatterns = [
url('^$', ListRankings.as_view()),
url(r'^event/(?P<event>[\d]+)/maistar/$',
ListGames.as_view(), name="maistar-game-list"),
@@ -28,4 +27,4 @@ urlpatterns = patterns(
ListPlayerGames.as_view(), name="maistar-player-games"),
url(r'^player/(?P<username>[\-\.\d\w]+)/maistar/(?P<season>[\d]+)/$',
ListPlayerGames.as_view(), name="maistar-player-games"),
)
]

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
import os

View File

@@ -96,7 +96,7 @@ class ActivationRequest(models.Model):
verbose_name = _('pending activation')
verbose_name_plural = _('pending activations')
def __unicode__(self):
def __str__(self):
return _("user registration for %s") % self.user
def activate(self):
@@ -215,7 +215,7 @@ class Membership(AbstractUser):
verbose_name = _('Membership')
verbose_name_plural = _('Memberships')
def __unicode__(self):
def __str__(self):
return self.username
def get_absolute_url(self):

View File

@@ -1,6 +1,5 @@
{% extends "base.html" %}
{% load i18n fieldset_extras %}
{% load url from future %}
{% block title %}{% trans "Registration"%}{% endblock %}
{% block teaser%}

View File

@@ -1,6 +1,6 @@
{% extends "base.html" %}
{% load i18n %}
{% load url from future %}
{% block title %}{% trans "Activation sent"%}{% endblock %}

View File

@@ -1,17 +1,16 @@
{% extends "base.html" %}
{% load i18n %}
{% load url from future %}
{% block title %}{% trans 'Login' %}{% endblock %}
{% block description %}Anmelden auf Kasu.at{% endblock %}
{% block extra_head %}
<link rel="canonical" href="{% url 'django.contrib.auth.views.login' %}"/>
<link rel="canonical" href="{% url 'login' %}"/>
{% endblock %}
{% block teaser %}<h1>{% trans 'Login' %}</h1>{% endblock %}
{% block maincontent %}
<form method="post" action="{% url 'django.contrib.auth.views.login' %}">
<form method="post" action="{% url 'login' %}">
<h2 class="grid_12">Auf der Seite Anmelden</h2>
<div class="grid_7">

View File

@@ -3,26 +3,38 @@ Created on 03.10.2011
@author: christian
"""
from django.conf.urls import * # @UnusedWildImport
import django.contrib.auth.views as auth_views
from django.conf.urls import url, include
from . import views
urlpatterns = patterns(
'',
url('', include('social_django.urls', namespace='social')),
url('', include('django.contrib.auth.urls')),
url(r'^register/$',
views.RegisterForm.as_view(),
name="membership-register"),
urlpatterns = [
url(r'^activate/(?P<activation_key>[\d\w]+)/$',
views.ActivateRegistration.as_view(),
name='membership-activate-registration'),
url(r'^activation_sent/$',
views.ActivationSent.as_view(),
name="membership-registration-complete"),
url(r'^login/$', auth_views.LoginView.as_view(), name='login'),
url(r'^logout/$', auth_views.LogoutView.as_view(), name='logout'),
url(r'^password_change/$', auth_views.PasswordChangeView.as_view(),
name='password_change'),
url(r'^password_change/done/$', auth_views.PasswordChangeDoneView.as_view(),
name='password_change_done'),
url(r'^password_reset/$', auth_views.PasswordResetView.as_view(),
name='password_reset'),
url(r'^password_reset/done/$', auth_views.PasswordResetDoneView.as_view(),
name='password_reset_done'),
url(r'^register/$', views.RegisterForm.as_view(),
name="membership-register"),
url(
r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
auth_views.PasswordResetConfirmView.as_view(),
name='password_reset_confirm'),
url(r'^reset/done/$', auth_views.PasswordResetCompleteView.as_view(),
name='password_reset_complete'),
url(r'^(?P<username>[\-\.\d\w]+)/$',
views.MembershipDetail.as_view(), name='membership-details'),
url(r'^(?P<username>[\-\.\d\w]+)/edit/$',
views.EditMembership.as_view(), name="membership-edit")
)
]

View File

@@ -3,7 +3,7 @@ import re
from django.core.urlresolvers import reverse
from django.core.serializers.json import DjangoJSONEncoder
from django.http import HttpResponse
from django.utils.encoding import smart_unicode, force_unicode
from django.utils.encoding import smart_text, force_text
try:
@@ -29,13 +29,13 @@ class LookupBase(object):
return []
def get_item_label(self, item):
return smart_unicode(item)
return smart_text(item)
def get_item_id(self, item):
return smart_unicode(item)
return smart_text(item)
def get_item_value(self, item):
return smart_unicode(item)
return smart_text(item)
def get_item(self, value):
return value
@@ -84,7 +84,7 @@ class LookupRegistry(object):
def register(self, lookup):
self.validate(lookup)
name = force_unicode(lookup.name())
name = force_text(lookup.name())
if name in self._registry:
raise LookupAlreadyRegistered(u'The name %s is already registered'
% name)
@@ -92,7 +92,7 @@ class LookupRegistry(object):
def unregister(self, lookup):
self.validate(lookup)
name = force_unicode(lookup.name())
name = force_text(lookup.name())
if name not in self._registry:
raise LookupNotRegistered(u'The name %s is not registered' % name)
del self._registry[name]

View File

@@ -7,7 +7,7 @@ from django.conf import settings
from django.forms import widgets
from django.forms.utils import flatatt
from django.utils import formats
from django.utils.encoding import force_unicode, force_text
from django.utils.encoding import force_text
from django.utils.html import conditional_escape
from django.utils.http import urlencode
from django.utils.safestring import mark_safe
@@ -98,7 +98,7 @@ class CheckboxInput(widgets.CheckboxInput):
if not (
value is True or value is False or value is None or value == ''): # @IgnorePep8
# Only add the 'value' attribute if a value is non-empty.
final_attrs['value'] = force_unicode(value)
final_attrs['value'] = force_text(value)
return mark_safe(u'<input%s /> %s' % (flatatt(final_attrs), title))
@@ -161,7 +161,7 @@ class Textarea(widgets.Widget):
final_attrs = self.build_attrs(attrs, name=name)
return mark_safe(u'<textarea%s>%s</textarea>' % (flatatt(final_attrs),
conditional_escape(
force_unicode(
force_text(
value))))
@@ -208,7 +208,7 @@ class LookupMultipleHiddenInput(widgets.MultipleHiddenInput):
if model and isinstance(v, model):
item = v
v = lookup.get_item_id(item)
input_attrs = dict(value=force_unicode(v), **final_attrs)
input_attrs = dict(value=force_text(v), **final_attrs)
if id_:
# An ID attribute was given. Add a numeric index as a suffix
# so that the inputs don't all have the same ID attribute.

View File

@@ -3,7 +3,8 @@ Created on 19.10.2011
@author: christian
"""
from BeautifulSoup import BeautifulSoup
from bs4 import BeautifulSoup
#TODO: Nach BeatutifulSoup 4 convertieren
class HtmlCleaner(object):
@@ -38,7 +39,7 @@ class HtmlCleaner(object):
tag_removed = False
def clean_attributes(self, tag):
for attr in tag._getAttrMap().keys():
for attr in list(tag.attrs.keys()):
if attr not in self.ACCEPTABELE_ATTRIBUTES:
del tag[attr]
elif tag[attr].count('script:'):
@@ -57,14 +58,14 @@ class HtmlCleaner(object):
@param fragment:
"""
while True:
soup = BeautifulSoup(fragment)
soup = BeautifulSoup(fragment, "html.parser")
self.tag_removed = False
self.counter += 1
for tag in soup.findAll(True):
for tag in soup.find_all(True):
self.clean_tag(tag)
fragment = unicode(soup)
fragment = str(soup)
if self.tag_removed:
continue
else:
break
return fragment
return fragment.strip()

View File

@@ -219,9 +219,9 @@ class Command(BaseCommand):
css_output = '%s/%s.css' % (CSS_ROOT,
site.domain.replace('.', '_'))
print _("Compressing CSS for %s") % site.name
print "Input Dir: %s" % css_input
print "Output File: %s" % css_output
print("Compressing CSS for {}".format(site.name))
print("Input Dir: {}".format(css_input))
print("Output File: {}".format(css_output))
try:
os.makedirs(css_input)
@@ -232,7 +232,7 @@ class Command(BaseCommand):
and append their content"""
for file_name in fnmatch.filter(sorted(os.listdir(css_input)),
'*.css'):
print ' Adding: %s' % file_name
print('Adding: {}'.format(file_name))
with open(os.path.join(css_input, file_name), 'r') as css_file:
css += css_file.read()
with open(css_output, 'w') as css_file:

View File

@@ -26,9 +26,9 @@ class Command(BaseCommand):
js_input = os.path.join(JS_ROOT, site.domain)
js_output = '%s/%s.js' % (JS_ROOT, site.domain.replace('.', '_'))
print _("Compressing JavaScript for %s") % site.name
print "Input Dir: %s" % js_input
print "Output File: %s" % js_output
print("Compressing JavaScript for {}".format(site.name))
print("Input Dir: {}".format(js_input))
print("Output File: %s".format(js_output))
try:
os.makedirs(js_input)
@@ -39,7 +39,7 @@ class Command(BaseCommand):
# content
js_files = fnmatch.filter(sorted(os.listdir(js_input)), '*.js')
for file_name in js_files:
print " Adding: %s..." % file_name
print(" Adding: {}...".format(file_name))
input_file_name = os.path.join(js_input, file_name)
with open(input_file_name, 'r') as input_file:
output += input_file.read()

46
src/utils/tests.py Normal file
View File

@@ -0,0 +1,46 @@
import unittest
import html_cleaner
class HtmlTestCase(unittest.TestCase):
known_html = (
('<STRONG>Fett!</STRONG>', '<strong>Fett!</strong>'),
('<a href="link.html" onclick="do_evil()">Bad Link</a>', '<a href="link.html">Bad Link</a>'),
('''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META http-equiv=Content-Type content="text/html; charset=iso-8859-1">
<META content="MSHTML 5.50.4919.2200" name=GENERATOR>
<STYLE></STYLE>
</HEAD>
<BODY bgColor=#ffffff>
<DIV><FONT face=Arial size=2>Hey Brad;</FONT></DIV>
<DIV><FONT face=Arial size=2></FONT>&nbsp;</DIV>
<DIV><FONT face=Arial size=2> 1) From your FAQ page at Webalizer.com the README
file link in question 19 to <A
href="ftp://ftp.mrunix.net/pub/webalizer/README">ftp://ftp.mrunix.net/pub/webalizer/README</A>&nbsp;brings
a 404 Page Not Found error message.</FONT></DIV>
<DIV><FONT face=Arial size=2></FONT>&nbsp;</DIV>
<DIV><FONT face=Arial size=2> 2) </FONT><FONT face=Arial size=2>My host recently
added Webalizer and I am trying to find the best way to keep the program running
correctly and to deny outsiders the ability to look at it. I would prefer not to
give others access to my stats.&nbsp; I do web design and at any given time have
client demos in various stages of completion and other things I'd prefer not to
have the general public see popping up in my stats.&nbsp; Does Webalizer have a
password protection mode or anything?</FONT></DIV>
<DIV><FONT face=Arial size=2></FONT>&nbsp;</DIV>
<DIV><FONT face=Arial size=2>XXXXXX XXXXXXX<BR>XXXXXXXXX Web Design<BR><A
href="http://www.xxxxxxxxxxxx.com">http://www.xxxxxxxxxxxx.com</A><BR>(xxx)
xxx-xxxx</FONT></DIV></BODY></HTML>
''',
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">'
)
)
def test_html_cleaner(self):
"""Ugly HTML Code has been made tidy"""
cleaner = html_cleaner.HtmlCleaner()
for original, tidy in self.known_html:
self.assertEqual(cleaner.clean_html(original), tidy)
if __name__ == '__main__':
unittest.main()