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 636c76fd78
commit 400aa95005
25 changed files with 219 additions and 121 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -24,10 +24,10 @@ class HanchanForm(forms.ModelForm):
class Meta(object): class Meta(object):
model = models.Hanchan model = models.Hanchan
fields = ('start', fields = ('start',
'player1', 'player1_input_score', # 'player1_comment', 'player1', 'player1_input_score',
'player2', 'player2_input_score', # 'player2_comment', 'player2', 'player2_input_score',
'player3', 'player3_input_score', # 'player3_comment', 'player3', 'player3_input_score',
'player4', 'player4_input_score', # 'player4_comment', 'player4', 'player4_input_score',
'comment') 'comment')
widgets = {'event': forms.HiddenInput(), widgets = {'event': forms.HiddenInput(),
'comment': forms.widgets.Textarea(attrs={'rows': 4, 'cols': 40}) 'comment': forms.widgets.Textarea(attrs={'rows': 4, 'cols': 40})
@@ -35,11 +35,14 @@ class HanchanForm(forms.ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(HanchanForm, self).__init__(*args, **kwargs) super(HanchanForm, self).__init__(*args, **kwargs)
# self.fields['event'].widget.attrs['disabled'] = True player_queryset = USER_MODEL.objects.filter(is_active=True,
for i in xrange(1, 4): membership=True)
for i in range(1, 4):
player = 'player%d' % i
player_input_score = 'player%d_input_score' % 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['size'] = 6
self.fields[player_input_score].widget.attrs['type'] = 'number' 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): def process_response(self, request, response):
# We only do this in POST request, to speedup the responsetime. # We only do this in POST request, to speedup the responsetime.
if request.method == 'POST': 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()) queue = cache.get('event_ranking_queue', set())
if len(queue) > 0: if len(queue) > 0:
self.recalculate_event_rankings(queue) self.recalculate_event_rankings(queue)
@@ -45,8 +48,6 @@ class DenormalizationUpdateMiddleware(object):
def recalculate_event_rankings(self, queue): def recalculate_event_rankings(self, queue):
# recalculate tournament (event) rankings: # recalculate tournament (event) rankings:
for event_id, user_id in queue: 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( ranking = models.EventRanking.objects.get_or_create(
event_id=event_id, user_id=user_id)[0] event_id=event_id, user_id=user_id)[0]
ranking.recalculate() ranking.recalculate()
@@ -54,10 +55,10 @@ class DenormalizationUpdateMiddleware(object):
return queue return queue
def recalulate_kyu_dan_ranking(self, queue): def recalulate_kyu_dan_ranking(self, queue):
for user_id in queue: for user_id, hanchan_start in queue:
ranking = models.KyuDanRanking.objects.get_or_create(user_id=user_id)[ ranking = models.KyuDanRanking.objects.get_or_create(
0] user_id=user_id)[0]
ranking.recalculate() ranking.recalculate(hanchan_start)
return queue return queue
def recalculate_ladder_ranking(self, 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

@@ -76,8 +76,7 @@ class EventRanking(models.Model):
self.good_hanchans += 1 if hanchan.placement == 2 else 0 self.good_hanchans += 1 if hanchan.placement == 2 else 0
self.avg_placement = sum_placement / self.hanchan_count self.avg_placement = sum_placement / self.hanchan_count
self.avg_score = sum_score / self.hanchan_count self.avg_score = sum_score / self.hanchan_count
self.save(force_update=True) self.save(force_update=True)
class Hanchan(models.Model): class Hanchan(models.Model):
@@ -95,7 +94,6 @@ class Hanchan(models.Model):
player1 = models.ForeignKey( player1 = models.ForeignKey(
settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL,
on_delete=models.CASCADE, on_delete=models.CASCADE,
limit_choices_to={'is_active': True, 'membership': True},
related_name='user_hanchan+', related_name='user_hanchan+',
verbose_name=_('Player 1')) verbose_name=_('Player 1'))
player1_input_score = models.IntegerField(_('Score')) player1_input_score = models.IntegerField(_('Score'))
@@ -115,7 +113,6 @@ class Hanchan(models.Model):
player2 = models.ForeignKey( player2 = models.ForeignKey(
settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL,
on_delete=models.CASCADE, on_delete=models.CASCADE,
limit_choices_to={'is_active': True, 'membership': True},
related_name='user_hanchan+', related_name='user_hanchan+',
verbose_name=_('Player 2')) verbose_name=_('Player 2'))
player2_input_score = models.IntegerField(_('Score')) player2_input_score = models.IntegerField(_('Score'))
@@ -135,7 +132,6 @@ class Hanchan(models.Model):
player3 = models.ForeignKey( player3 = models.ForeignKey(
settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL,
on_delete=models.CASCADE, on_delete=models.CASCADE,
limit_choices_to={'is_active': True, 'membership': True},
related_name='user_hanchan+', related_name='user_hanchan+',
verbose_name=_('Player 3')) verbose_name=_('Player 3'))
player3_input_score = models.IntegerField(_('Score')) player3_input_score = models.IntegerField(_('Score'))
@@ -155,7 +151,6 @@ class Hanchan(models.Model):
player4 = models.ForeignKey( player4 = models.ForeignKey(
settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL,
on_delete=models.CASCADE, on_delete=models.CASCADE,
limit_choices_to={'is_active': True, 'membership': True},
related_name='user_hanchan+', related_name='user_hanchan+',
verbose_name=_('Player 4')) verbose_name=_('Player 4'))
player4_input_score = models.IntegerField(_('Score')) player4_input_score = models.IntegerField(_('Score'))
@@ -205,11 +200,11 @@ class Hanchan(models.Model):
try: try:
self.clean_fields() self.clean_fields()
except ValidationError as e: except ValidationError as exception:
print e.update_error_dict(errors) exception.update_error_dict(errors)
return return
for i in xrange(1, 5): for i in range(1, 5):
player = getattr(self, 'player%d' % i) player = getattr(self, 'player%d' % i)
input_score = getattr(self, 'player%d_input_score' % i) input_score = getattr(self, 'player%d_input_score' % i)
score_sum += input_score score_sum += input_score
@@ -309,7 +304,7 @@ class Hanchan(models.Model):
@property @property
def player_list(self): def player_list(self):
player_list = [] player_list = []
for i in xrange(1, 5): for i in range(1, 5):
player_list.append({ player_list.append({
'user': getattr(self, 'player%d' % i), 'user': getattr(self, 'player%d' % i),
'input_score': getattr(self, 'player%d_input_score' % 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'], return sorted(player_list, key=lambda player: player['input_score'],
reverse=True) reverse=True)
def save(self, **kwargs): def save(self, recalculate=True, **kwargs):
self.season = self.event.mahjong_season or self.start.year self.season = self.event.mahjong_season or self.start.year
self.full_clean() self.full_clean()
self.compute_player_placements() if recalculate:
self.compute_player_placements()
update_ranking(sender=Hanchan, instance=self)
return models.Model.save(self, **kwargs) return models.Model.save(self, **kwargs)
@@ -435,7 +432,7 @@ class KyuDanRanking(models.Model):
else: else:
return reverse('player-kyu-score', args=[self.user.username]) 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 Fetches all valid Hanchans from this Player and recalculates his
Kyu/Dan Ranking. Kyu/Dan Ranking.
@@ -449,14 +446,23 @@ class KyuDanRanking(models.Model):
self.good_hanchans = 0 self.good_hanchans = 0
self.won_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() self.update_rank()
valid_hanchans = Hanchan.objects.confirmed_hanchans(user=self.user) valid_hanchans = Hanchan.objects.confirmed_hanchans(user=self.user)
valid_hanchans = valid_hanchans.order_by('start') valid_hanchans = valid_hanchans.order_by('start')
if self.legacy_date: if self.legacy_date:
valid_hanchans = valid_hanchans.filter(start__gt=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() self.hanchan_count += valid_hanchans.count()
for hanchan in valid_hanchans: 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.get_playerdata(self.user)
hanchan.bonus_points = 0 hanchan.bonus_points = 0
hanchan.player_comment = u"" hanchan.player_comment = u""
@@ -469,7 +475,7 @@ class KyuDanRanking(models.Model):
self.won_hanchans += 1 if hanchan.placement == 1 else 0 self.won_hanchans += 1 if hanchan.placement == 1 else 0
self.good_hanchans += 1 if hanchan.placement == 2 else 0 self.good_hanchans += 1 if hanchan.placement == 2 else 0
hanchan.update_playerdata(self.user) hanchan.update_playerdata(self.user)
hanchan.save(force_update=True) hanchan.save(recalculate=False)
self.save(force_update=True) self.save(force_update=True)
def update_hanchan_points(self, hanchan): def update_hanchan_points(self, hanchan):
@@ -537,7 +543,7 @@ class KyuDanRanking(models.Model):
if self.dan_points > min_points: if self.dan_points > min_points:
self.dan = dan_rank self.dan = dan_rank
break break
if self.dan > old_dan: if old_dan == None or self.dan > old_dan:
self.wins_in_a_row = 0 self.wins_in_a_row = 0
elif self.kyu_points < 1: elif self.kyu_points < 1:
self.kyu_points = 0 self.kyu_points = 0
@@ -600,10 +606,16 @@ class SeasonRanking(models.Model):
def update_ranking(sender, instance, **kwargs): def update_ranking(sender, instance, **kwargs):
for user in (instance.player1, instance.player2, instance.player3, instance.player4): for user in (instance.player1, instance.player2, instance.player3, instance.player4):
logger.debug("marking %s's kyu/dan for recalculation", user) logger.debug(
set_dirty(user=user.id) "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: 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) set_dirty(user=user.id, season=instance.season)
logger.debug("marking season %d for recalculation.", instance.season) logger.debug("marking season %d for recalculation.", instance.season)
set_dirty(season=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) set_dirty(event=instance.event_id, user=user.id)
models.signals.pre_delete.connect(update_ranking, sender=Hanchan) 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 @author: christian
""" """
from django.conf.urls import * # @UnusedWildImport
from django.views.generic import RedirectView from django.views.generic import RedirectView
from django.conf.urls import url
import views from . import views
urlpatterns = patterns( urlpatterns = [
'',
url(r'^$', RedirectView.as_view( url(r'^$', RedirectView.as_view(
url='/ranking/mahjong-ladder/', permanent=True) url='/ranking/mahjong-ladder/', permanent=True)
), ),
@@ -42,4 +40,4 @@ urlpatterns = patterns(
name="kyudanranking-list"), name="kyudanranking-list"),
url(r'^mahjong/(?P<order_by>[\+\-\w]+)/$', url(r'^mahjong/(?P<order_by>[\+\-\w]+)/$',
views.KyuDanRankingList.as_view(), name="kyudanranking-list"), views.KyuDanRankingList.as_view(), name="kyudanranking-list"),
) ]

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -3,26 +3,38 @@ Created on 03.10.2011
@author: christian @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 from . import views
urlpatterns = [
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"),
url(r'^activate/(?P<activation_key>[\d\w]+)/$', url(r'^activate/(?P<activation_key>[\d\w]+)/$',
views.ActivateRegistration.as_view(), views.ActivateRegistration.as_view(),
name='membership-activate-registration'), name='membership-activate-registration'),
url(r'^activation_sent/$', url(r'^activation_sent/$',
views.ActivationSent.as_view(), views.ActivationSent.as_view(),
name="membership-registration-complete"), 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]+)/$', url(r'^(?P<username>[\-\.\d\w]+)/$',
views.MembershipDetail.as_view(), name='membership-details'), views.MembershipDetail.as_view(), name='membership-details'),
url(r'^(?P<username>[\-\.\d\w]+)/edit/$', url(r'^(?P<username>[\-\.\d\w]+)/edit/$',
views.EditMembership.as_view(), name="membership-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.urlresolvers import reverse
from django.core.serializers.json import DjangoJSONEncoder from django.core.serializers.json import DjangoJSONEncoder
from django.http import HttpResponse from django.http import HttpResponse
from django.utils.encoding import smart_unicode, force_unicode from django.utils.encoding import smart_text, force_text
try: try:
@@ -29,13 +29,13 @@ class LookupBase(object):
return [] return []
def get_item_label(self, item): def get_item_label(self, item):
return smart_unicode(item) return smart_text(item)
def get_item_id(self, item): def get_item_id(self, item):
return smart_unicode(item) return smart_text(item)
def get_item_value(self, item): def get_item_value(self, item):
return smart_unicode(item) return smart_text(item)
def get_item(self, value): def get_item(self, value):
return value return value
@@ -84,7 +84,7 @@ class LookupRegistry(object):
def register(self, lookup): def register(self, lookup):
self.validate(lookup) self.validate(lookup)
name = force_unicode(lookup.name()) name = force_text(lookup.name())
if name in self._registry: if name in self._registry:
raise LookupAlreadyRegistered(u'The name %s is already registered' raise LookupAlreadyRegistered(u'The name %s is already registered'
% name) % name)
@@ -92,7 +92,7 @@ class LookupRegistry(object):
def unregister(self, lookup): def unregister(self, lookup):
self.validate(lookup) self.validate(lookup)
name = force_unicode(lookup.name()) name = force_text(lookup.name())
if name not in self._registry: if name not in self._registry:
raise LookupNotRegistered(u'The name %s is not registered' % name) raise LookupNotRegistered(u'The name %s is not registered' % name)
del self._registry[name] del self._registry[name]

View File

@@ -7,7 +7,7 @@ from django.conf import settings
from django.forms import widgets from django.forms import widgets
from django.forms.utils import flatatt from django.forms.utils import flatatt
from django.utils import formats 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.html import conditional_escape
from django.utils.http import urlencode from django.utils.http import urlencode
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
@@ -98,7 +98,7 @@ class CheckboxInput(widgets.CheckboxInput):
if not ( if not (
value is True or value is False or value is None or value == ''): # @IgnorePep8 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. # 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)) 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) final_attrs = self.build_attrs(attrs, name=name)
return mark_safe(u'<textarea%s>%s</textarea>' % (flatatt(final_attrs), return mark_safe(u'<textarea%s>%s</textarea>' % (flatatt(final_attrs),
conditional_escape( conditional_escape(
force_unicode( force_text(
value)))) value))))
@@ -208,7 +208,7 @@ class LookupMultipleHiddenInput(widgets.MultipleHiddenInput):
if model and isinstance(v, model): if model and isinstance(v, model):
item = v item = v
v = lookup.get_item_id(item) 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_: if id_:
# An ID attribute was given. Add a numeric index as a suffix # An ID attribute was given. Add a numeric index as a suffix
# so that the inputs don't all have the same ID attribute. # 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 @author: christian
""" """
from BeautifulSoup import BeautifulSoup from bs4 import BeautifulSoup
#TODO: Nach BeatutifulSoup 4 convertieren
class HtmlCleaner(object): class HtmlCleaner(object):
@@ -38,7 +39,7 @@ class HtmlCleaner(object):
tag_removed = False tag_removed = False
def clean_attributes(self, tag): 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: if attr not in self.ACCEPTABELE_ATTRIBUTES:
del tag[attr] del tag[attr]
elif tag[attr].count('script:'): elif tag[attr].count('script:'):
@@ -57,14 +58,14 @@ class HtmlCleaner(object):
@param fragment: @param fragment:
""" """
while True: while True:
soup = BeautifulSoup(fragment) soup = BeautifulSoup(fragment, "html.parser")
self.tag_removed = False self.tag_removed = False
self.counter += 1 self.counter += 1
for tag in soup.findAll(True): for tag in soup.find_all(True):
self.clean_tag(tag) self.clean_tag(tag)
fragment = unicode(soup) fragment = str(soup)
if self.tag_removed: if self.tag_removed:
continue continue
else: else:
break break
return fragment return fragment.strip()

View File

@@ -219,9 +219,9 @@ class Command(BaseCommand):
css_output = '%s/%s.css' % (CSS_ROOT, css_output = '%s/%s.css' % (CSS_ROOT,
site.domain.replace('.', '_')) site.domain.replace('.', '_'))
print _("Compressing CSS for %s") % site.name print("Compressing CSS for {}".format(site.name))
print "Input Dir: %s" % css_input print("Input Dir: {}".format(css_input))
print "Output File: %s" % css_output print("Output File: {}".format(css_output))
try: try:
os.makedirs(css_input) os.makedirs(css_input)
@@ -232,7 +232,7 @@ class Command(BaseCommand):
and append their content""" and append their content"""
for file_name in fnmatch.filter(sorted(os.listdir(css_input)), for file_name in fnmatch.filter(sorted(os.listdir(css_input)),
'*.css'): '*.css'):
print ' Adding: %s' % file_name print('Adding: {}'.format(file_name))
with open(os.path.join(css_input, file_name), 'r') as css_file: with open(os.path.join(css_input, file_name), 'r') as css_file:
css += css_file.read() css += css_file.read()
with open(css_output, 'w') as css_file: 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_input = os.path.join(JS_ROOT, site.domain)
js_output = '%s/%s.js' % (JS_ROOT, site.domain.replace('.', '_')) js_output = '%s/%s.js' % (JS_ROOT, site.domain.replace('.', '_'))
print _("Compressing JavaScript for %s") % site.name print("Compressing JavaScript for {}".format(site.name))
print "Input Dir: %s" % js_input print("Input Dir: {}".format(js_input))
print "Output File: %s" % js_output print("Output File: %s".format(js_output))
try: try:
os.makedirs(js_input) os.makedirs(js_input)
@@ -39,7 +39,7 @@ class Command(BaseCommand):
# content # content
js_files = fnmatch.filter(sorted(os.listdir(js_input)), '*.js') js_files = fnmatch.filter(sorted(os.listdir(js_input)), '*.js')
for file_name in js_files: 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) input_file_name = os.path.join(js_input, file_name)
with open(input_file_name, 'r') as input_file: with open(input_file_name, 'r') as input_file:
output += input_file.read() 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()