Another Step in the Quest to clean up the code base.

This commit is contained in:
2017-09-08 07:19:50 +02:00
parent ce218080b2
commit b3ab9798b5
229 changed files with 1915 additions and 15175 deletions

View File

@@ -0,0 +1 @@
"""A simple ladder ranking system for the game mai-star."""

View File

@@ -1,17 +1,17 @@
# -*- encoding: utf-8 -*-
"""
Created on 19.09.2011
@author: christian
"""
""" Admin Interface to manipulate the maistar ranking """
from django.contrib import admin
from django.utils.translation import ugettext as _
from . import forms, models
def recalculate(modeladmin, request, queryset): # @UnusedVariable
def recalculate(modeladmin, request, queryset):
""" Force an recalculation of the seleceted Ranking objects.
:param modeladmin: The current ModelAdmin.
:param request: An HttpRequest representing the current request.
:param queryset: A QuerySet containing the objects selected by the user.
"""
if isinstance(modeladmin, RankingAdmin):
seasons = set()
for ranking in queryset:
@@ -25,6 +25,7 @@ recalculate.short_description = _("Recalculate")
class RankingAdmin(admin.ModelAdmin):
"""Admin interface for Mai-Star season ladder ranking entries."""
actions = [recalculate]
list_display = (
'season', 'placement', 'user', 'avg_placement', 'avg_score',
@@ -35,6 +36,7 @@ class RankingAdmin(admin.ModelAdmin):
class GameAdmin(admin.ModelAdmin):
"""Admin interface to manage Mai-Star game scores."""
actions = [recalculate]
# date_hierarchy = 'event__start'
fields = (

View File

@@ -1,5 +1,4 @@
# -*- encoding: utf-8 -*-
__author__ = 'christian'
"""Django Forms to add and edit Mai-Star games."""
from django import forms
from django.utils.translation import ugettext as _
@@ -8,10 +7,12 @@ from . import models
class GameForm(forms.ModelForm):
"""To add/edit a Mai-Star game for the ladder ranking."""
error_css_class = 'error'
required_css_class = 'required'
class Meta(object):
"""hide the metadata in the form."""
fields = [
'player1', 'player1_score',
'player2', 'player2_score',
@@ -24,14 +25,15 @@ class GameForm(forms.ModelForm):
model = models.Game
def clean(self):
"""Check that every player occours only once per game."""
cleaned_data = super(GameForm, self).clean()
players_in_game = set()
for player_nr in (
'player1', 'player2', 'player3', 'player4', 'player5', 'player6'):
current_player = cleaned_data.get(player_nr)
for player_no in range(1, 6):
player = 'player{nr}'.format(nr=player_no)
current_player = cleaned_data.get('player')
if current_player and current_player in players_in_game:
msg = _("%s may only participate once." % current_player)
self._errors[player_nr] = self.error_class([msg])
del cleaned_data[player_nr]
self._errors[player] = self.error_class([msg])
del cleaned_data[player]
players_in_game.add(current_player)
return cleaned_data

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: kasu.mahjong_ranking\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.at@gmail.com>\n"
"Language-Team: Kasu <verein@kasu.at>\n"
@@ -19,7 +19,7 @@ msgstr ""
"X-Generator: Poedit 1.8.9\n"
"X-Translated-Using: django-rosetta 0.7.2\n"
#: maistar_ranking/admin.py:24
#: maistar_ranking/admin.py:19
msgid "Recalculate"
msgstr "Neuberechnen"
@@ -85,7 +85,7 @@ msgstr "Mai-Star Spiel mit {0} vom {1:%Y-%m-%d}"
#: maistar_ranking/templates/maistar_ranking/game_form.html:5
#: maistar_ranking/templates/maistar_ranking/game_form.html:16
#: maistar_ranking/templates/maistar_ranking/game_list.html:27
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:45
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:44
msgid "Edit Game"
msgstr "Spiel bearbeiten"
@@ -121,12 +121,12 @@ msgid "Place"
msgstr "Platz"
#: maistar_ranking/templates/maistar_ranking/game_list.html:19
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:37
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:36
msgid "Points"
msgstr "Punkte"
#: maistar_ranking/templates/maistar_ranking/game_list.html:24
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:42
#: maistar_ranking/templates/maistar_ranking/player_game_list.html:41
msgid "Delete Game"
msgstr "Spiel löschen"

View File

@@ -1,4 +1,4 @@
# -*- encoding: utf-8 -*-
"""ORM Models for the Mai-Star ranking"""
import logging
@@ -7,15 +7,13 @@ from django.db import models
from django.utils.translation import ugettext as _
from events.models import Event
from membership.models import Membership
from . import settings, managers
class Game(models.Model):
"""
Ein kompettes Spiel Mai-Star bestehend aus 6 Spielern
"""
"""to record a complete game with 6 different players."""
_player_list = list()
event = models.ForeignKey(Event, related_name='maistargame_set')
comment = models.TextField(_('Comment'), blank=True)
player1 = models.ForeignKey(
@@ -71,34 +69,29 @@ class Game(models.Model):
)
def get_absolute_url(self):
"""
URL zur Hanchanliste des Events wo diese Hanchan gelistet wurde.
"""
"""URL to the event subpage that lists the Mai-Star games."""
url = reverse('maistar-game-list',
kwargs={'event': self.event.pk})
return u'%(url)s#%(pk)d' % {'url': url, 'pk': self.pk}
@property
def player_list(self):
try:
return self._player_list
except AttributeError:
self._player_list = list()
for nr in range(1, 7):
self._player_list.append({
'user': getattr(self, 'player%d' % nr),
'score': getattr(self, 'player%d_score' % nr),
'placement': getattr(self, 'player%d_placement' % nr),
})
"""return a dict() with all 6 player names, scores and placements.
It will be cached and reused for more perfomance."""
if self._player_list:
return self._player_list
for player_no in range(1, 7):
self._player_list.append(dict(
user=getattr(self, 'player%d' % player_no),
score=getattr(self, 'player%d_score' % player_no),
placement=getattr(self, 'player%d_placement' % player_no)
))
return self._player_list
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
u"""
Bestimmt die Platzierung eines jeden Spielers noch vor dem speichern.
Außerdem wird eine Kommasperierte Liste der Spiele mitgespeichert.
"""
logging.debug("Berechne die Platzierungen neu...")
def save(self, **kwargs):
"""recalculate the rankings before saving.
Also self.player_names will be filled with an comma sperated list of
all 6 player names."""
game_date = self.event.start.date()
player_tuples = [
(self.player1.id, self.player1.username, self.player1_score),
@@ -138,12 +131,11 @@ class Game(models.Model):
self.season = season_start.year
else:
self.season = season_start.year - 1
super(Game, self).save(force_insert=force_insert,
force_update=force_update, using=using,
update_fields=update_fields)
super(Game, self).save(**kwargs)
class Ranking(models.Model):
"""the player scores in the ladder for one season. """
user = models.ForeignKey(settings.AUTH_USER_MODEL)
season = models.PositiveSmallIntegerField(_("Season"))
placement = models.PositiveIntegerField(blank=True, null=True)
@@ -155,22 +147,24 @@ class Ranking(models.Model):
objects = managers.LadderManager()
class Meta(object):
"""Display rankings by placement, best players first."""
ordering = ('-season', 'placement', 'avg_placement', '-avg_score',)
def __str__(self):
return "Mai-Star Ranking: %s, Season: %d" % (self.user, self.season)
return "Mai-Star Ranking: {user!s}, Season: {season!d}".format(
user=self.user,
season=int(self.season)
)
def get_absolute_url(self):
"""URL to the subpage of the user profile, listing all Games."""
return reverse('maistar-player-games', kwargs={
'username': self.user.username,
'season': self.season
})
def recalculate(self):
logging.info(
u'Recalculate Mai-Star Ranking for Player %s in Season %s',
self.user, self.season
)
"""Recalculate the Mai-Star Ranking for this Player in this Season."""
self.placement = None
self.avg_placement = None
self.avg_score = None
@@ -199,6 +193,8 @@ class Ranking(models.Model):
def update_maistar_ranking(sender, instance, **kwargs):
"""A Django signal hook to trigger a recalculation of the rankings as soon
as a Mai-Star game has been added, deleted, or modified."""
for player in instance.player_list:
ranking, created = Ranking.objects.get_or_create(
user=player['user'],

View File

@@ -1,30 +1,24 @@
# -*- encoding: utf-8 -*-
"""
Created on 03.10.2011
""" Definition of the URL paths to access the views of the Maistar ranking. """
@author: christian
"""
from django.conf.urls import url
from django.views.generic import RedirectView
from .views import DeleteGame, ListGames, ListPlayerGames, \
ListRankings, GameForm
from . import views
urlpatterns = [
url('^$', ListRankings.as_view()),
url('^$', views.ListRankings.as_view()),
url(r'^event/(?P<event>[\d]+)/maistar/$',
ListGames.as_view(), name="maistar-game-list"),
views.ListGames.as_view(), name="maistar-game-list"),
url(r'^event/(?P<event>[\d]+)/maistar/add/$',
GameForm.as_view(), name="maistar-add-game"),
views.GameForm.as_view(), name="maistar-add-game"),
url(r'^maistar/(?P<game>[\d]+)/edit/$',
GameForm.as_view(), name="maistar-edit-game"),
views.GameForm.as_view(), name="maistar-edit-game"),
url(r'^maistar/(?P<game>[\d]+)/delete/$',
DeleteGame.as_view(), name="maistar-delete-game"),
url(r'^maistar/$', ListRankings.as_view(), name="maistar-ranking"),
views.DeleteGame.as_view(), name="maistar-delete-game"),
url(r'^maistar/$',
views.ListRankings.as_view(), name="maistar-ranking"),
url(r'^maistar/(?P<season>[\d]+)/$',
ListRankings.as_view(), name="maistar-ranking"),
views.ListRankings.as_view(), name="maistar-ranking"),
url(r'^player/(?P<username>[\-\.\d\w]+)/maistar/$',
ListPlayerGames.as_view(), name="maistar-player-games"),
views.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"),
views.ListPlayerGames.as_view(), name="maistar-player-games"),
]

View File

@@ -1,18 +1,15 @@
# -*- encoding: utf-8 -*-
"""Views to display the Mai-Star Ladder an Mai-Star game scores."""
from datetime import date
from django.contrib import auth
from django.core.urlresolvers import reverse
from django.shortcuts import get_object_or_404
from django.utils.translation import gettext as _
from django.views import generic
from events.models import Event
from events.views import EventDetailMixin
from membership.models import Membership
from utils.mixins import LoginRequiredMixin
from utils.mixins import PermissionRequiredMixin
from events.mixins import EventDetailMixin
from django.contrib.auth.mixins import PermissionRequiredMixin
from mahjong_ranking.views import PlayerScore
from . import forms, models
@@ -120,5 +117,5 @@ class ListRankings(generic.ListView):
context['season_list'] = models.Ranking.objects.get_seasons()
context['latest_games'] = models.Game.objects.filter(confirmed=True)[
:3]
context['latest_events'] = Event.objects.latest_events(num=3)
context['latest_events'] = Event.objects.upcoming(limit=3)
return context