Eine Menge Aufräumarbeiten.

* Eine Testsuite um Mahrjong Ranking Berechnungen zu testen
* Erste Arbeiten um die Workarounds aus dem "utils" Paket los zu werden.
* Vieles am Code umformatiert für PEP8 conformität
This commit is contained in:
2017-06-07 13:25:30 +02:00
parent cf0bbb4c8f
commit a26a91c360
93 changed files with 33531 additions and 2737 deletions

View File

@@ -33,6 +33,9 @@ logger = logging.getLogger('kasu.mahjong_ranking')
def set_dirty(event=None, season=None, user=None, hanchan_date=None):
key_to_add = None
queue_name = None
if season and user:
key_to_add = (season, user)
queue_name = 'ladder_ranking_queue'

View File

@@ -26,6 +26,8 @@ def recalculate(modeladmin, request, queryset):
for ladder_ranking in queryset:
set_dirty(user=ladder_ranking.user_id,
season=ladder_ranking.season)
recalculate.short_description = _("Recalculate")
@@ -33,6 +35,8 @@ def confirm(modeladmin, request, queryset):
for hanchan in queryset:
hanchan.confirmed = True
hanchan.save()
confirm.short_description = _("Confirm")
@@ -40,6 +44,8 @@ def unconfirm(modeladmin, request, queryset):
for hanchan in queryset:
hanchan.confirmed = False
hanchan.save()
unconfirm.short_description = _('Set unconfirmed')

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -6,11 +6,9 @@ Created on 04.10.2011
@author: christian
"""
from django.contrib.auth import get_user_model
import django.forms
from django.utils import timezone
from django import forms
from django.utils.translation import ugettext as _
from utils.html5 import forms
from . import models
USER_MODEL = get_user_model()
@@ -19,7 +17,7 @@ USER_MODEL = get_user_model()
class HanchanForm(forms.ModelForm):
error_css_class = 'error'
required_css_class = 'required'
start = forms.DateTimeField(label=_('start'), required=True)
start = forms.SplitDateTimeField(label=_('start'), required=True)
class Meta(object):
model = models.Hanchan
@@ -29,8 +27,9 @@ class HanchanForm(forms.ModelForm):
'player3', 'player3_input_score',
'player4', 'player4_input_score',
'comment')
widgets = {'event': forms.HiddenInput(),
'comment': forms.widgets.Textarea(attrs={'rows': 4, 'cols': 40})
widgets = {
'event': forms.HiddenInput(),
'comment': forms.widgets.Textarea(attrs={'rows': 4, 'cols': 40})
}
def __init__(self, *args, **kwargs):
@@ -45,7 +44,6 @@ class HanchanForm(forms.ModelForm):
self.fields[player].queryset = player_queryset
class HanchanAdminForm(HanchanForm):
class Meta(object):
@@ -53,12 +51,12 @@ class HanchanAdminForm(HanchanForm):
fields = HanchanForm.Meta.fields + ('confirmed',)
class SeasonSelectForm(django.forms.Form):
season = django.forms.ChoiceField(label='', choices=('a', 'b', 'c'))
class SeasonSelectForm(forms.Form):
season = forms.ChoiceField(label='', choices=('a', 'b', 'c'))
def __init__(self, user, *args, **kwargs):
super(SeasonSelectForm, self).__init__(args, kwargs)
season_list = models.LadderRanking.objects.filter(user=user)
season_list = season_list.select_related('user')
season_list = season_list.values_list('season__id', 'season__name')
self.fields['season'] = django.forms.ChoiceField(choices=season_list)
self.fields['season'] = forms.ChoiceField(choices=season_list)

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: kasu.mahjong_ranking\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-09-28 00:25+0200\n"
"POT-Creation-Date: 2017-05-10 23:16+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,376 +19,376 @@ msgstr ""
"X-Generator: Poedit 1.8.9\n"
"X-Translated-Using: django-rosetta 0.7.6\n"
#: src/mahjong_ranking/admin.py:29
#: mahjong_ranking/admin.py:29
msgid "Recalculate"
msgstr "Neuberechnen"
#: src/mahjong_ranking/admin.py:36
#: mahjong_ranking/admin.py:36
msgid "Confirm"
msgstr "Bestätigen"
#: src/mahjong_ranking/admin.py:43
#: mahjong_ranking/admin.py:43
msgid "Set unconfirmed"
msgstr "Als unbestätigt markieren"
#: src/mahjong_ranking/forms.py:22
#: mahjong_ranking/forms.py:22
msgid "start"
msgstr "Beginn"
#: src/mahjong_ranking/models.py:91
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:14
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:13
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:15
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:15
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:10
#: mahjong_ranking/models.py:90
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:14
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:13
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:15
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:15
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:10
msgid "Start"
msgstr "Beginn"
#: src/mahjong_ranking/models.py:92
#: mahjong_ranking/models.py:91
msgid "This is crucial to get the right Hanchans that scores"
msgstr "Wichtig damit die richtigen Hanchans in die Wertung kommen."
#: src/mahjong_ranking/models.py:97
#: mahjong_ranking/models.py:98
msgid "Player 1"
msgstr "Spieler 1"
#: src/mahjong_ranking/models.py:98 src/mahjong_ranking/models.py:100
#: src/mahjong_ranking/models.py:115 src/mahjong_ranking/models.py:117
#: src/mahjong_ranking/models.py:132 src/mahjong_ranking/models.py:134
#: src/mahjong_ranking/models.py:149 src/mahjong_ranking/models.py:151
#: src/mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:19
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:21
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:16
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:43
#: src/mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:31
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:32
#: mahjong_ranking/models.py:99 mahjong_ranking/models.py:101
#: mahjong_ranking/models.py:118 mahjong_ranking/models.py:120
#: mahjong_ranking/models.py:137 mahjong_ranking/models.py:139
#: mahjong_ranking/models.py:156 mahjong_ranking/models.py:158
#: mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:19
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:21
#: mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:16
#: mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:19
#: mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:35
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:32
msgid "Score"
msgstr "Punkte"
#: src/mahjong_ranking/models.py:110 src/mahjong_ranking/models.py:127
#: src/mahjong_ranking/models.py:144 src/mahjong_ranking/models.py:161
#: src/mahjong_ranking/models.py:163
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:44
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:18
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:17
#: mahjong_ranking/models.py:111 mahjong_ranking/models.py:130
#: mahjong_ranking/models.py:149 mahjong_ranking/models.py:168
#: mahjong_ranking/models.py:170
#: mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:20
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:18
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:17
msgid "Comment"
msgstr "Kommentar"
#: src/mahjong_ranking/models.py:114
#: mahjong_ranking/models.py:117
msgid "Player 2"
msgstr "Spieler 2"
#: src/mahjong_ranking/models.py:131
#: mahjong_ranking/models.py:136
msgid "Player 3"
msgstr "Spieler 3"
#: src/mahjong_ranking/models.py:148
#: mahjong_ranking/models.py:155
msgid "Player 4"
msgstr "Spieler 4"
#: src/mahjong_ranking/models.py:164
#: mahjong_ranking/models.py:171
msgid "Has been Confirmed"
msgstr "Wurde bestätigt"
#: src/mahjong_ranking/models.py:166
#: mahjong_ranking/models.py:173
msgid "Only valid and confirmed Hanchans will be counted in the rating."
msgstr "Nur gültige und bestätigte Hanchans kommen in die Wertung."
#: src/mahjong_ranking/models.py:171 src/mahjong_ranking/models.py:547
#: src/mahjong_ranking/templates/mahjong_ranking/ladder_redbox.html:29
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:63
#: mahjong_ranking/models.py:178 mahjong_ranking/models.py:565
#: mahjong_ranking/templates/mahjong_ranking/ladder_redbox.html:29
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:63
msgid "Season"
msgstr "Saison"
#: src/mahjong_ranking/models.py:176
#: mahjong_ranking/models.py:183
msgid "Hanchan"
msgstr "Hanchan"
#: src/mahjong_ranking/models.py:177
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:17
#: mahjong_ranking/models.py:184
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:17
msgid "Hanchans"
msgstr "Hanchans"
#: src/mahjong_ranking/models.py:180
#: mahjong_ranking/models.py:187
msgid "Hanchan from {0:%Y-%m-%d} at {0:%H:%M} with {1}"
msgstr "Hanchan vom {0:%Y-%m-%d} um {0:%H:%M} mit {1}"
#: src/mahjong_ranking/models.py:207
#: mahjong_ranking/models.py:214
#, python-format
msgid "%s can't attend the same game multiple times"
msgstr "%s kann an einem Spiel nicht mehrfach teilnehmen."
#: src/mahjong_ranking/models.py:215
#: mahjong_ranking/models.py:222
msgid "Games in the future may not be added, Dr. Brown"
msgstr "Spiele aus der Zukunft dürfen noch nicht erfasst werden. Dr. Brown."
#: src/mahjong_ranking/models.py:217
#: mahjong_ranking/models.py:224
msgid "Only games during the event are allowed"
msgstr "Nur Spiele während der Veranstaltung zählen."
#: src/mahjong_ranking/models.py:220
#: mahjong_ranking/models.py:227
msgid "Gamescore is lower then 100.000 Pt."
msgstr "Spielstand ist weniger als 100.000 Punkte"
#: src/mahjong_ranking/models.py:222
#: mahjong_ranking/models.py:229
msgid "Gamescore is over 100.000 Pt."
msgstr "Spielstand ist über 100.000 Punkte."
#: src/mahjong_ranking/models.py:344
#: mahjong_ranking/models.py:353
msgid "Kyū/Dan Ranking"
msgstr "Kyū/Dan Wertung"
#: src/mahjong_ranking/models.py:345
#: mahjong_ranking/models.py:354
msgid "Kyū/Dan Rankings"
msgstr "Kyū/Dan Wertungen"
#: src/mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:7
#: mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:7
msgid "Played Hanchans"
msgstr "Gespielte Hanchans"
#: src/mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:18
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:15
#: mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:18
#: mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:15
msgid "Place"
msgstr "Platz"
#: src/mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:21
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:18
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:17
#: mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:21
#: mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:18
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:17
msgid "Dan Points"
msgstr "Dan Punkte"
#: src/mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:23
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:20
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:16
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:18
#: mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:23
#: mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:20
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:16
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:18
msgid "Kyu Points"
msgstr "Kyu Punkte"
#: src/mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:37
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:4
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:33
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:44
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:33
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:41
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:52
#: mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:37
#: mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:4
#: mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:33
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:44
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:33
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:41
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:52
msgid "Delete Hanchan"
msgstr "Hanchan löschen"
#: src/mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:43
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:4
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:38
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:47
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:36
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:44
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:55
#: mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:43
#: mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:4
#: mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:14
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:47
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:36
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:44
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:55
msgid "Edit Hanchan"
msgstr "Hanchan bearbeiten"
#: src/mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:48
#: mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:48
msgid "No Hanchan has been added to this event yet."
msgstr "Für diese Veranstaltung wurde noch keine Hanchan eingetragen."
#: src/mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:54
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:51
#: mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:54
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:51
msgid "Edit Event"
msgstr "Veranstaltung bearbeiten"
#: src/mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:55
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:52
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:4
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:38
#: mahjong_ranking/templates/mahjong_ranking/eventhanchan_list.html:55
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:52
#: mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:4
#: mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:14
msgid "Add Hanchan"
msgstr "Hanchan hinzufügen"
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:4
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:5
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:4
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:5
msgid "Tournament Ranking"
msgstr "Turnierwertung"
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:12
#: src/mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:26
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:23
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:12
#: mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:30
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:23
msgid "Rank"
msgstr "Rang"
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:13
#: src/mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:13
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:24
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:13
#: mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:17
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:24
msgid "Avatar"
msgstr "Avatar"
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:14
#: src/mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:16
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:25
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:14
#: mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:20
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:25
msgid "Nickname"
msgstr "Spitzname"
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:15
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:26
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:15
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:26
msgid "Name"
msgstr "Name"
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:16
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:27
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:16
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:27
msgid "Average"
msgstr "Durchschnitt"
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:20
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:15
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:15
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:16
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:16
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:31
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:20
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:15
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:15
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:16
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:16
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:31
msgid "Placement"
msgstr "Platzierung"
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:22
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:33
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:22
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:33
msgid "count"
msgstr "Anzahl"
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:23
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:34
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:23
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:34
msgid "good"
msgstr "gut"
#: src/mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:24
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:35
#: mahjong_ranking/templates/mahjong_ranking/eventranking_list.html:24
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:35
msgid "won"
msgstr "gewonnen"
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:39
#: mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:39
msgid "Cancel"
msgstr "Abbruch"
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:40
#: mahjong_ranking/templates/mahjong_ranking/hanchan_confirm_delete.html:40
msgid "Delete"
msgstr "Löschen"
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:42
#: mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:18
msgid "Player"
msgstr "Spieler"
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:82
#: mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:58
msgid "Total"
msgstr "Total"
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:94
#: mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:71
msgid "back"
msgstr "Zurück"
#: src/mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:95
#: mahjong_ranking/templates/mahjong_ranking/hanchan_form.html:72
msgid "save"
msgstr "Speichern"
#: src/mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:4
#: src/mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:5
#: mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:4
#: mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:9
msgid "Player List"
msgstr "Spieler Liste"
#: src/mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:21
#: mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:25
msgid "Full Name"
msgstr "Voller Name"
#: src/mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:36
#: mahjong_ranking/templates/mahjong_ranking/kyudanranking_list.html:40
msgid "Games Total"
msgstr "Spiele total"
#: src/mahjong_ranking/templates/mahjong_ranking/ladder_redbox.html:3
#: mahjong_ranking/templates/mahjong_ranking/ladder_redbox.html:3
msgid "Latest Hanchans"
msgstr "Letzten Hanchans"
#: src/mahjong_ranking/templates/mahjong_ranking/ladder_redbox.html:15
#: mahjong_ranking/templates/mahjong_ranking/ladder_redbox.html:15
msgid "Latest Events"
msgstr "Letzte Veranstaltungen"
#: src/mahjong_ranking/templates/mahjong_ranking/ladder_redbox.html:27
#: mahjong_ranking/templates/mahjong_ranking/ladder_redbox.html:27
msgid "Ladder Archive"
msgstr "Ladder Archiv"
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:4
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:5
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:4
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:5
msgid "Dan Score for"
msgstr "Dan Wertung für"
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:8
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:8
msgid "Hanchans that apply to the Dan Score"
msgstr "Hanchans welche zur Dan Wertung zählen"
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:12
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:13
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:13
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:12
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:13
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:13
msgid "Date"
msgstr "Datum"
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:13
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:12
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:14
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:14
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:13
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:12
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:14
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:14
msgid "Event"
msgstr "Veranstaltung"
#: src/mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:16
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:14
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:17
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:17
#: mahjong_ranking/templates/mahjong_ranking/player_dan_score.html:16
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:14
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:17
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:17
msgid "Players"
msgstr "Spieler"
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:4
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:6
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:4
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:6
msgid "Unconfirmed Hanchans from"
msgstr "Nicht bestätigte Hanchans von"
#: src/mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:9
#: mahjong_ranking/templates/mahjong_ranking/player_invalid_score.html:9
msgid "Invalid hanchans with"
msgstr "Ungültige Hanchans mit"
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:4
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:6
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:4
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:6
msgid "Kyu Score for"
msgstr "Kyu Wertung für"
#: src/mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:9
#: mahjong_ranking/templates/mahjong_ranking/player_kyu_score.html:9
msgid "Hanchans that apply to the Kyu Score"
msgstr "Hanchans welche zur Kyu Wertung zählen"
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:4
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:5
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:4
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:5
msgid "Ladder Score for"
msgstr "Ladder Wertung für"
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:8
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:8
msgid "Hanchans that apply to the Ladder Score"
msgstr "Hanchans welche in der Ladder zählen"
#: src/mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:69
#: mahjong_ranking/templates/mahjong_ranking/player_ladder_score.html:69
msgid "Go"
msgstr "Los"
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:11
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:11
msgid "End"
msgstr "Ende"
#: src/mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:12
#: mahjong_ranking/templates/mahjong_ranking/seasonranking_list.html:12
msgid "Participants"
msgstr "Teilnehmer"
#: src/mahjong_ranking/views.py:97
#: mahjong_ranking/views.py:97
#, python-format
msgid "%s has been updated successfully."
msgstr "%s wurde erfolgreich aktualisiert."
#: src/mahjong_ranking/views.py:100
#: mahjong_ranking/views.py:100
#, python-format
msgid "%s has been added successfully. You can now add a new one."
msgstr "%s wurde erfolgreich hinzugefügt. Du kannst eine neue eintragen."
#: src/mahjong_ranking/views.py:118 src/mahjong_ranking/views.py:134
#: mahjong_ranking/views.py:118 mahjong_ranking/views.py:134
msgid "Event does not exist"
msgstr "Veranstaltung existiert nicht"
#: src/mahjong_ranking/views.py:199
#: mahjong_ranking/views.py:199
msgid "No user found matching the name {}"
msgstr "Kein Benutzer mit dem Namen %s gefunden"

View File

@@ -10,31 +10,32 @@ from mahjong_ranking.models import SeasonRanking
from openpyxl import Workbook
def geneate_seasonexcel(json_data):
wb = Workbook()
worksheet = wb.active
worksheet.append([
'Rang', 'Spitzname',
'⌀ Platz', '⌀ Punkte',
'Hanchans', 'Gut', 'Gewonnen'
])
json_data = json_data.values()
json_data = sorted(json_data, key=itemgetter('placement'))
for row in json_data:
worksheet.append([
row['placement'], row['username'],
row['avg_placement'], row['avg_score'],
row['hanchan_count'],
row['good_hanchans'], row['won_hanchans']
])
wb.save("sample.xlsx")
class Command(BaseCommand):
help = "Exports the SeasonRankings"
def geneate_seasonexcel(self, json_data):
wb = Workbook()
worksheet = wb.active
worksheet.append([
'Rang', 'Spitzname',
'⌀ Platz', '⌀ Punkte',
'Hanchans', 'Gut', 'Gewonnen'
])
json_data = json_data.values()
json_data = sorted(json_data, key=itemgetter('placement'))
for row in json_data:
worksheet.append([
row['placement'], row['username'],
row['avg_placement'], row['avg_score'],
row['hanchan_count'],
row['good_hanchans'], row['won_hanchans']
])
wb.save("sample.xlsx")
def handle(self, *args, **options):
season_json = SeasonRanking.objects.json_data()
self.geneate_seasonexcel(season_json)
geneate_seasonexcel(season_json)

View File

@@ -14,4 +14,3 @@ class Command(BaseCommand):
def handle(self, *args, **options):
for ranking in models.KyuDanRanking.objects.all():
ranking.recalculate()

View File

@@ -42,14 +42,22 @@ class HanchanManager(models.Manager):
season = season or date.today().year
return self.confirmed_hanchans(user=user, season=season)
def user_hanchans(self, user, **kwargs):
def user_hanchans(self, user, since=None, **kwargs):
"""
:param user: User Object, or an player_id as integer
:param since: optional a date value since when you want to hanchans
:return:
"""
queryset = self.filter(
models.Q(player1=user) | models.Q(player2=user) |
models.Q(player3=user) | models.Q(player4=user)
)
queryset = queryset.select_related().order_by('-start')
if since:
queryset = queryset.filter(start__gte=since)
if kwargs:
queryset = queryset.filter(**kwargs)
queryset = queryset.select_related().order_by('-start')
for hanchan in queryset:
hanchan.get_playerdata(user)
return queryset

View File

@@ -20,9 +20,12 @@ 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()))
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)

View File

@@ -19,21 +19,25 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='hanchan',
name='player1_comment',
field=models.CharField(verbose_name='Kommentar', max_length=255, editable=False, blank=True),
field=models.CharField(
verbose_name='Kommentar', max_length=255, editable=False, blank=True),
),
migrations.AlterField(
model_name='hanchan',
name='player2_comment',
field=models.CharField(verbose_name='Kommentar', max_length=255, editable=False, blank=True),
field=models.CharField(
verbose_name='Kommentar', max_length=255, editable=False, blank=True),
),
migrations.AlterField(
model_name='hanchan',
name='player3_comment',
field=models.CharField(verbose_name='Kommentar', max_length=255, editable=False, blank=True),
field=models.CharField(
verbose_name='Kommentar', max_length=255, editable=False, blank=True),
),
migrations.AlterField(
model_name='hanchan',
name='player4_comment',
field=models.CharField(verbose_name='Kommentar', max_length=255, editable=False, blank=True),
field=models.CharField(
verbose_name='Kommentar', max_length=255, editable=False, blank=True),
),
]

View File

@@ -19,21 +19,25 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='hanchan',
name='player1_comment',
field=models.CharField(verbose_name='Anmerkung', max_length=255, editable=False, blank=True),
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),
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),
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),
field=models.CharField(
verbose_name='Anmerkung', max_length=255, editable=False, blank=True),
),
]

View File

@@ -4,7 +4,6 @@
# werden dürfen.
from __future__ import division
from datetime import date
from django.conf import settings
from django.core.exceptions import ValidationError
@@ -371,7 +370,8 @@ class KyuDanRanking(models.Model):
self.wins_in_a_row = 0
if self.dan and self.wins_in_a_row >= 3 and self.dan < 9:
logger.info('adding bonuspoints for 3 wins in a row for %s', self.user)
logger.info(
'adding bonuspoints for 3 wins in a row for %s', self.user)
new_dan_rank = self.dan + 1
new_dan_points = DAN_RANKS_DICT[new_dan_rank] + 1
bonus_points = new_dan_points - self.dan_points
@@ -379,7 +379,8 @@ class KyuDanRanking(models.Model):
logger.debug("Stats for %s:", self.user)
logger.debug("current dan_points: %d", self.dan_points)
logger.debug("current dan: %d", self.dan)
logger.debug("min required points for the next dan: %d", new_dan_points)
logger.debug(
"min required points for the next dan: %d", new_dan_points)
logger.debug("bonus points to add: %d", bonus_points)
hanchan.dan_points += bonus_points
@@ -404,7 +405,8 @@ class KyuDanRanking(models.Model):
).order_by('-start')
last_hanchan_this_event = hanchans_this_event[0]
if hanchan != last_hanchan_this_event:
return False # Das braucht nur am Ende eines Turnieres gemacht werden.
# Das braucht nur am Ende eines Turnieres gemacht werden.
return False
else:
event_ranking = EventRanking.objects.get(
user=self.user,
@@ -455,14 +457,13 @@ class KyuDanRanking(models.Model):
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
""" 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""
@@ -476,6 +477,16 @@ class KyuDanRanking(models.Model):
self.good_hanchans += 1 if hanchan.placement == 2 else 0
hanchan.update_playerdata(self.user)
hanchan.save(recalculate=False)
logger.debug(
'id: %(id)d, start: %(start)s, placement: %(placement)d, '
'score: %(score)d, kyu points: %(kyu_points)d, dan points: '
'%(dan_points)d, bonus points: %(bonus_points)d',
{'id': hanchan.pk, 'start': hanchan.start,
'placement': hanchan.placement, 'score': hanchan.game_score,
'kyu_points': hanchan.kyu_points or 0,
'dan_points': hanchan.dan_points or 0,
'bonus_points': hanchan.bonus_points or 0}
)
self.save(force_update=True)
def update_hanchan_points(self, hanchan):
@@ -543,7 +554,7 @@ class KyuDanRanking(models.Model):
if self.dan_points > min_points:
self.dan = dan_rank
break
if old_dan == None or self.dan > old_dan:
if old_dan is None or self.dan > old_dan:
self.wins_in_a_row = 0
elif self.kyu_points < 1:
self.kyu_points = 0
@@ -608,7 +619,7 @@ def update_ranking(sender, instance, **kwargs):
for user in (instance.player1, instance.player2, instance.player3, instance.player4):
logger.debug(
"marking %(user)s's kyu/dan for recalculation since %(start)s",
{'user':user, 'start':str(instance.start.date())}
{'user': user, 'start': str(instance.start.date())}
)
set_dirty(user=user.id, hanchan_date=instance.start.date())
if instance.season:
@@ -622,5 +633,6 @@ def update_ranking(sender, instance, **kwargs):
logger.debug("marking event %s for recalculation.", instance.event)
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)

View File

@@ -29,7 +29,10 @@
<label for="season">{% trans 'Season' %}</label>
<select id="season" name="season" size="1" onChange="window.location.href = document.season_select.season.options[document.season_select.season.selectedIndex].value;">
{% for season_link in season_list%}
<option value="{% url 'mahjong-ladder' season_link %}" {% ifequal season season_link %}selected="selected"{% endifequal %}>{{ season_link }}</option>
<option
value="{% url 'mahjong-ladder' season_link %}"
{% ifequal season season_link %} selected="selected"{% endifequal %}>{{ season_link }}
</option>
{% endfor %}
</select>
</form>

View File

@@ -63,7 +63,9 @@
<label for="season">{% trans 'Season' %}:</label>
<select id="season" name="season" size="1">
{% for season_link in season_list%}
<option value="{{ season_link }}" {% ifequal season season_link %}selected="selected"{% endifequal %}>{{ season_link }}</option>
<option
{% ifequal season season_link %} selected="selected"{% endifequal %}
value="{{ season_link }}">{{ season_link }}</option>
{% endfor %}
</select>
<button type="submit">{% trans 'Go' %}</button>

View File

@@ -4,14 +4,101 @@ when you run "manage.py test".
Replace this with more appropriate tests for your application.
"""
import random
from django.test import TestCase
from mahjong_ranking.models import Hanchan, KyuDanRanking
class SimpleTest(TestCase):
class KyuDanTest(TestCase):
"""
Unittest to check if the hanchan calculation works against the rulebook.
"""
equal_attrs = ('dan', 'dan_points', 'kyu', 'kyu_points', 'good_hanchans',
'won_hanchans', 'hanchan_count')
def test_basic_addition(self):
fixtures = [
'test_membership.json',
'test_events.json',
'test_hanchans.json',
'test_event_rankings.json',
'test_kyu_dan_rankings.json'
]
def recalc(self):
"""
Tests that 1 + 1 always equals 2.
Test if a Kyu/Dan Ranking recalculation gives the same result as stored.
:return:
"""
self.assertEqual(1 + 1, 2)
for ranking in KyuDanRanking.objects.all():
original = {a: getattr(ranking, a) for a in self.equal_attrs}
ranking.recalculate()
for attr in self.equal_attrs:
self.assertEqual(
original[attr],
getattr(ranking, attr),
"Recalculation was different! user: {user}, attribute: "
"{attr}, original: {original}, recalc: {recalc}".format(
user=ranking.user, attr=attr, original=original[attr],
recalc=getattr(ranking, attr))
)
def test_partial_recalc(self):
"""
Test if partial recalclulation gives the same results.
:return:
"""
for ranking in KyuDanRanking.objects.all():
original = {a: getattr(ranking, a) for a in self.equal_attrs}
confirmed_hanchans = Hanchan.objects.confirmed_hanchans(
user=ranking.user,
since=ranking.legacy_date
)
rnd = random.randrange(confirmed_hanchans.count())
since = confirmed_hanchans[rnd].start
print(since)
ranking.recalculate(hanchan_start=since)
for attr in self.equal_attrs:
self.assertEqual(
original[attr],
getattr(ranking, attr),
"partial Recalculation was different! user: {user}, "
"attribute: {attr}, original: {original}, recalc: "
"{recalc}".format(
user=ranking.user, attr=attr, original=original[attr],
recalc=getattr(ranking, attr))
)
def test_points_sum(self):
"""
Test if the sum of the kyu / dan points equals the value in the Ranking.
:return: None
"""
for ranking in KyuDanRanking.objects.all():
dan_kyu = 'dan_points' if ranking.dan else 'kyu_points'
points = {
'dan_points': ranking.legacy_dan_points or 0,
'kyu_points': ranking.legacy_kyu_points or 0
}
confirmed_hanchans = Hanchan.objects.confirmed_hanchans(
user=ranking.user,
since=ranking.legacy_date
)
for hanchan in confirmed_hanchans:
hanchan.get_playerdata(ranking.user)
points[dan_kyu] += getattr(hanchan, dan_kyu) or 0
self.assertEqual(
points[dan_kyu],
getattr(ranking, dan_kyu),
"{dan_kyu} for {player} won't compute! ranking: {ranking}, sum: {sum}".format(
dan_kyu=dan_kyu, player=ranking.user,
ranking=getattr(ranking, dan_kyu), sum=points[dan_kyu])
)