Fehlerbereinigung.

Mahjong Ranking berechnet nun die richtigen Ränge zu den legendären Kyu/Dan Punkten.

Stablie Version bevor die Datenstruktur des Mahjongrankings vereinfacht wird.
This commit is contained in:
Christian Berg
2015-08-18 20:25:35 +02:00
committed by Christian Berg
parent 617b7131fe
commit 8981d4b261
1177 changed files with 1713 additions and 10150 deletions

View File

@@ -28,7 +28,7 @@ DAN_RANKS = (
)
DAN_RANKS_DICT = dict([(dan, points) for points, dan in DAN_RANKS])
MIN_HANCHANS_FOR_LADDER = 10
MIN_HANCHANS_FOR_LADDER = 5
logger = getLogger('kasu.mahjong_ranking')

View File

@@ -38,7 +38,7 @@ recalculate.short_description = _("Recalculate")
class PlayerInline(admin.TabularInline):
extra = 4
formset = PlayerFormSet
readonly_fields = ('placement', 'kyu_points', 'dan_points', 'bonus_points',
readonly_fields = ('game_score', 'placement', 'kyu_points', 'dan_points', 'bonus_points',
'comment',)
max_num = 4
model = models.Player
@@ -47,7 +47,7 @@ class PlayerInline(admin.TabularInline):
class EventRankingAdmin(admin.ModelAdmin):
list_filter = ['event']
list_display = ('placement', 'user', 'event', 'avg_placement', 'avg_score',
'hanchan_count', 'good_hanchans', 'won_hanchans', 'dirty')
'hanchan_count', 'good_hanchans', 'won_hanchans')
list_display_links = ('user',)
actions = [recalculate]
@@ -70,21 +70,32 @@ class HanchanAdmin(admin.ModelAdmin):
class KyuDanAdmin(admin.ModelAdmin):
actions = [recalculate]
list_display = ('user', 'kyu', 'kyu_points', 'dan', 'dan_points',
'hanchan_count', 'dirty')
'hanchan_count')
readonly_fields = ('user', 'kyu', 'kyu_points', 'dan', 'dan_points')
fieldsets = (
('Aktueller Dan/Kyū', {
'fields': ('user', ('kyu', 'kyu_points'), ('dan', 'dan_points')),
'classes': ('grp-collapse grp-open',),
}),
('Frühere Aufzeichnungen', {
'fields': ('legacy_date', ('legacy_kyu_points', 'legacy_dan_points')),
'classes': ('grp-collapse grp-closed',),
}),
)
class LadderRankingAdmin(admin.ModelAdmin):
actions = [recalculate]
list_display = ('placement', 'season', 'user', 'avg_placement',
'avg_score', 'hanchan_count', 'good_hanchans',
'won_hanchans', 'dirty')
'won_hanchans')
list_display_links = ('user',)
list_filter = ('season',)
class LadderSeasonAdmin(admin.ModelAdmin):
actions = [recalculate]
list_display = ('name', 'start', 'end', 'dirty')
list_display = ('name', 'start', 'end')
admin.site.register(models.EventRanking, EventRankingAdmin)

View File

@@ -65,24 +65,30 @@ class PlayerForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(PlayerForm, self).__init__(*args, **kwargs)
self.fields['input_score'].widget.attrs['size'] = 6
self.fields['input_score'].widget.attrs['type'] = 'number'
self.fields['bonus_points'].widget.attrs['readonly'] = True
self.fields['bonus_points'].widget.attrs['size'] = 2
self.fields['comment'].widget.attrs['readonly'] = True
self.fields['score'].widget.attrs['size'] = 6
self.fields['score'].widget.attrs['type'] = 'number'
class Meta(object):
model = models.Player
fields = ('hanchan', 'user', 'score', 'bonus_points', 'comment')
fields = ('hanchan', 'user', 'input_score', 'bonus_points', 'comment')
class PlayerInlineFormSet(BaseInlineFormSet):
def clean(self):
"""Checks that no two articles have the same title."""
if any(self.errors):
return
playerset = set()
for form in self.forms:
if form.is_valid() and not form.cleaned_data.get('user'):
raise forms.ValidationError(
_("A valid Hanchan needs 4 players"))
raise forms.ValidationError(_("A valid Hanchan needs 4 players"))
player = form.cleaned_data['user']
if player in playerset:
message = _("Player %s cant attend the game multiple times.") % player
raise forms.ValidationError(message)
playerset.add(player)
self.validate_unique()
return False

View File

@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: kasu.mahjong_ranking\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-01-05 19:23+0100\n"
"PO-Revision-Date: 2015-01-04 11:58+0100\n"
"POT-Creation-Date: 2015-08-16 11:34+0200\n"
"PO-Revision-Date: 2015-08-16 11:39+0200\n"
"Last-Translator: Christian Berg <xeniac.at@gmail.com>\n"
"Language-Team: Kasu <verein@kasu.at>\n"
"Language: de\n"
@@ -17,43 +17,48 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Translated-Using: django-rosetta 0.7.2\n"
"X-Generator: Poedit 1.7.1\n"
"X-Generator: Poedit 1.8.3\n"
#: admin.py:35
msgid "Recalculate"
msgstr "Neuberechnen"
#: forms.py:21
#: forms.py:24
msgid "start"
msgstr "Beginn"
#: forms.py:40 models.py:168
#: forms.py:41 models.py:164
msgid "It's not allowed to enter future games."
msgstr "Spiele in der Zukunft sind nicht erlaubt."
#: forms.py:43
#: forms.py:44
msgid "Only games running during this event are allowed."
msgstr "Nur Spiele während der Veranstaltung sind erlaubt."
#: forms.py:88
#: forms.py:86
msgid "A valid Hanchan needs 4 players"
msgstr "Eine gültige Hanchan braucht 4 Spieler"
#: models.py:84 models.py:613 templates/mahjong_ranking/hanchan_form.html:30
#: forms.py:89
#, python-format
msgid "Player %s cant attend the game multiple times."
msgstr "%s kann an einem Spiel nicht mehrfach teilnehmen."
#: models.py:78 models.py:617 templates/mahjong_ranking/hanchan_form.html:26
#: templates/mahjong_ranking/player_dan_score.html:19
#: templates/mahjong_ranking/player_invalid_score.html:18
msgid "Comment"
msgstr "Kommentar"
#: models.py:85
#: models.py:79
msgid "Has been Confirmed"
msgstr "Wurde bestätigt"
#: models.py:87
#: models.py:81
msgid "Only valid and confirmed Hanchans will be counted in the rating."
msgstr "Nur gültige und bestätigte Hanchans kommen in die Wertung."
#: models.py:93 templates/mahjong_ranking/hanchan_form.html:23
#: models.py:87 templates/mahjong_ranking/hanchan_form.html:19
#: templates/mahjong_ranking/player_dan_score.html:17
#: templates/mahjong_ranking/player_invalid_score.html:15
#: templates/mahjong_ranking/player_kyu_score.html:18
@@ -61,7 +66,7 @@ msgstr "Nur gültige und bestätigte Hanchans kommen in die Wertung."
msgid "Players"
msgstr "Spieler"
#: models.py:97 templates/mahjong_ranking/ladderranking_list.html:8
#: models.py:91 templates/mahjong_ranking/ladderranking_list.html:8
#: templates/mahjong_ranking/player_dan_score.html:15
#: templates/mahjong_ranking/player_invalid_score.html:14
#: templates/mahjong_ranking/player_kyu_score.html:16
@@ -69,62 +74,118 @@ msgstr "Spieler"
msgid "Start"
msgstr "Beginn"
#: models.py:98
#: models.py:92
msgid "This is crucial to get the right Hanchans that scores"
msgstr "Wichtig damit die richtigen Hanchans in die Wertung kommen."
#: models.py:99
#: models.py:93
msgid "Is Valid"
msgstr "Ist gültig"
#: models.py:103
#: models.py:97
msgid "Hanchan"
msgstr "Hanchan"
#: models.py:104
#: models.py:98 templates/mahjong_ranking/eventranking_list.html:18
msgid "Hanchans"
msgstr "Hanchans"
#: models.py:125
#: models.py:119
msgid "For a Hanchan exactly 4 players are needed."
msgstr "Eine Hanchan benötigt genau 4 Spieler."
#: models.py:166
#: models.py:160
msgid "Hanchan has no event"
msgstr "Hanchan gehört zu keiner Veranstaltung."
#: models.py:170
#: models.py:162
#, fuzzy
#| msgid "Hanchan has no event"
msgid "Hanchan has no start time set"
msgstr "Hanchan gehört zu keiner Veranstaltung."
#: models.py:166
msgid "Only games during the event are allowed"
msgstr "Nur Spiele während der Veranstaltung zählen."
#: models.py:238
#: models.py:236
msgid "Kyū/Dan Ranking"
msgstr "Kyū/Dan Wertung"
#: models.py:239
#: models.py:237
msgid "Kyū/Dan Rankings"
msgstr "Kyū/Dan Wertungen"
#: models.py:500
#: models.py:505
msgid "Ladder Season"
msgstr "Saison"
#: models.py:501
#: models.py:506
msgid "Ladder Seasons"
msgstr "Saisons"
#: views.py:148 views.py:165
msgid "Event does not exist"
msgstr "Veranstaltung existiert nicht"
#: templates/mahjong_ranking/eventhanchan_list.html:7
msgid "Played Hanchans"
msgstr "Gespielte Hanchans"
#: views.py:206
msgid "Season does not exist"
msgstr "Saison existiert nicht"
#: templates/mahjong_ranking/eventhanchan_list.html:15
msgid "Place"
msgstr "Platz"
#: views.py:300
#, python-format
msgid "No user found matching the name %s"
msgstr "Kein Benutzer mit dem Namen %s gefunden"
#: templates/mahjong_ranking/eventhanchan_list.html:16
#: templates/mahjong_ranking/eventranking_list.html:22
#: templates/mahjong_ranking/hanchan_form.html:24
#: templates/mahjong_ranking/kyudanranking_list.html:30
#: templates/mahjong_ranking/ladderranking_list.html:29
msgid "Score"
msgstr "Punkte"
#: templates/mahjong_ranking/eventhanchan_list.html:18
#: templates/mahjong_ranking/player_dan_score.html:18
msgid "Dan Points"
msgstr "Dan Punkte"
#: templates/mahjong_ranking/eventhanchan_list.html:20
#: templates/mahjong_ranking/player_invalid_score.html:17
#: templates/mahjong_ranking/player_kyu_score.html:19
msgid "Kyu Points"
msgstr "Kyu Punkte"
#: templates/mahjong_ranking/eventhanchan_list.html:34
#: templates/mahjong_ranking/hanchan_confirm_delete.html:4
#: templates/mahjong_ranking/hanchan_confirm_delete.html:10
#: templates/mahjong_ranking/player_dan_score.html:45
#: templates/mahjong_ranking/player_invalid_score.html:34
#: templates/mahjong_ranking/player_kyu_score.html:42
#: templates/mahjong_ranking/player_ladder_score.html:39
msgid "Delete Hanchan"
msgstr "Hanchan löschen"
#: templates/mahjong_ranking/eventhanchan_list.html:37
#: templates/mahjong_ranking/hanchan_form.html:4
#: templates/mahjong_ranking/hanchan_form.html:16
#: templates/mahjong_ranking/player_dan_score.html:48
#: templates/mahjong_ranking/player_invalid_score.html:37
#: templates/mahjong_ranking/player_kyu_score.html:45
#: templates/mahjong_ranking/player_ladder_score.html:42
msgid "Edit Hanchan"
msgstr "Hanchan bearbeiten"
#: templates/mahjong_ranking/eventhanchan_list.html:41
msgid "No Hanchan has been added to this event yet."
msgstr "Für diese Veranstaltung wurde noch keine Hanchan eingetragen."
#: templates/mahjong_ranking/eventhanchan_list.html:47
#: templates/mahjong_ranking/eventranking_list.html:55
msgid "Edit Event"
msgstr "Veranstaltung bearbeiten"
#: templates/mahjong_ranking/eventhanchan_list.html:48
#: templates/mahjong_ranking/eventranking_list.html:56
#: templates/mahjong_ranking/hanchan_form.html:4
#: templates/mahjong_ranking/hanchan_form.html:16
msgid "Add Hanchan"
msgstr "Hanchan hinzufügen"
#: templates/mahjong_ranking/eventranking_list.html:5
#: templates/mahjong_ranking/eventranking_list.html:6
@@ -168,14 +229,6 @@ msgstr "Durchschnitt"
msgid "Placement"
msgstr "Platzierung"
#: templates/mahjong_ranking/eventranking_list.html:22
#: templates/mahjong_ranking/hanchan_form.html:28
#: templates/mahjong_ranking/hanchan_list.html:16
#: templates/mahjong_ranking/kyudanranking_list.html:30
#: templates/mahjong_ranking/ladderranking_list.html:29
msgid "Score"
msgstr "Punkte"
#: templates/mahjong_ranking/eventranking_list.html:23
#: templates/mahjong_ranking/ladderranking_list.html:30
msgid "count"
@@ -191,118 +244,30 @@ msgstr "gut"
msgid "won"
msgstr "gewonnen"
#: templates/mahjong_ranking/eventranking_list.html:58
#: templates/mahjong_ranking/ladderranking_list.html:77
msgid "Ladder Archive"
msgstr "Ladder Archiv"
#: templates/mahjong_ranking/eventranking_list.html:65
#: templates/mahjong_ranking/ladderranking_list.html:71
msgid "Latest Events"
msgstr "Letzte Veranstaltungen"
#: templates/mahjong_ranking/eventranking_list.html:72
#: templates/mahjong_ranking/ladderranking_list.html:61
msgid "Latest Hanchans"
msgstr "Letzten Hanchans"
#: templates/mahjong_ranking/hanchan_confirm_delete.html:4
#: templates/mahjong_ranking/hanchan_confirm_delete.html:10
#: templates/mahjong_ranking/hanchan_list.html:36
#: templates/mahjong_ranking/player_dan_score.html:47
#: templates/mahjong_ranking/player_invalid_score.html:34
#: templates/mahjong_ranking/player_kyu_score.html:42
#: templates/mahjong_ranking/player_ladder_score.html:39
msgid "Delete Hanchan"
msgstr "Hanchan löschen"
#: templates/mahjong_ranking/hanchan_confirm_delete.html:14
#: templates/mahjong_ranking/hanchan_confirm_delete.html:15
#: templates/mahjong_ranking/hanchan_confirm_delete.html:16
msgid "Cancel"
msgstr "Abbruch"
#: templates/mahjong_ranking/hanchan_confirm_delete.html:18
#: templates/mahjong_ranking/hanchan_confirm_delete.html:19
#: templates/mahjong_ranking/hanchan_list.html:35
#: templates/mahjong_ranking/player_dan_score.html:46
#: templates/mahjong_ranking/player_invalid_score.html:34
#: templates/mahjong_ranking/player_kyu_score.html:42
#: templates/mahjong_ranking/player_ladder_score.html:39
#: templates/mahjong_ranking/hanchan_confirm_delete.html:17
msgid "Delete"
msgstr "Löschen"
#: templates/mahjong_ranking/hanchan_form.html:5
#: templates/mahjong_ranking/hanchan_form.html:20
#: templates/mahjong_ranking/hanchan_list.html:41
#: templates/mahjong_ranking/player_dan_score.html:52
#: templates/mahjong_ranking/player_invalid_score.html:37
#: templates/mahjong_ranking/player_kyu_score.html:45
#: templates/mahjong_ranking/player_ladder_score.html:42
msgid "Edit Hanchan"
msgstr "Hanchan bearbeiten"
#: templates/mahjong_ranking/hanchan_form.html:5
#: templates/mahjong_ranking/hanchan_form.html:20
#: templates/mahjong_ranking/hanchan_list.html:54
msgid "Add Hanchan"
msgstr "Hanchan hinzufügen"
#: templates/mahjong_ranking/hanchan_form.html:27
#: templates/mahjong_ranking/hanchan_form.html:23
msgid "User"
msgstr "Benutzer"
#: templates/mahjong_ranking/hanchan_form.html:29
#: templates/mahjong_ranking/hanchan_form.html:25
msgid "Bonus"
msgstr "Bonus"
#: templates/mahjong_ranking/hanchan_form.html:51
#: templates/mahjong_ranking/hanchan_form.html:46
msgid "back"
msgstr "Zurück"
#: templates/mahjong_ranking/hanchan_form.html:52
#: templates/mahjong_ranking/hanchan_form.html:47
msgid "save"
msgstr "Speichern"
#: templates/mahjong_ranking/hanchan_list.html:7
msgid "Played Hanchans"
msgstr "Gespielte Hanchans"
#: templates/mahjong_ranking/hanchan_list.html:15
msgid "Place"
msgstr "Platz"
#: templates/mahjong_ranking/hanchan_list.html:18
#: templates/mahjong_ranking/player_dan_score.html:18
msgid "Dan Points"
msgstr "Dan Punkte"
#: templates/mahjong_ranking/hanchan_list.html:20
#: templates/mahjong_ranking/player_invalid_score.html:17
#: templates/mahjong_ranking/player_kyu_score.html:19
msgid "Kyu Points"
msgstr "Kyu Punkte"
#: templates/mahjong_ranking/hanchan_list.html:40
#: templates/mahjong_ranking/player_dan_score.html:51
#: templates/mahjong_ranking/player_invalid_score.html:37
#: templates/mahjong_ranking/player_kyu_score.html:45
#: templates/mahjong_ranking/player_ladder_score.html:42
msgid "Edit"
msgstr "Bearbeiten"
#: templates/mahjong_ranking/hanchan_list.html:45
msgid "No Hanchan has been added to this event yet."
msgstr "Für diese Veranstaltung wurde noch keine Hanchan eingetragen."
#: templates/mahjong_ranking/hanchan_list.html:52
#: templates/mahjong_ranking/hanchan_list.html:54
msgid "Add"
msgstr "Hinzufügen"
#: templates/mahjong_ranking/hanchan_list.html:52
msgid "Edit Event"
msgstr "Veranstaltung bearbeiten"
#: templates/mahjong_ranking/kyudanranking_list.html:4
#: templates/mahjong_ranking/kyudanranking_list.html:5
msgid "Player List"
@@ -324,7 +289,19 @@ msgstr "Ende"
msgid "Participants"
msgstr "Teilnehmer"
#: templates/mahjong_ranking/ladderranking_list.html:79
#: templates/mahjong_ranking/ladderranking_list.html:59
msgid "Latest Hanchans"
msgstr "Letzten Hanchans"
#: templates/mahjong_ranking/ladderranking_list.html:68
msgid "Latest Events"
msgstr "Letzte Veranstaltungen"
#: templates/mahjong_ranking/ladderranking_list.html:74
msgid "Ladder Archive"
msgstr "Ladder Archiv"
#: templates/mahjong_ranking/ladderranking_list.html:76
#: templates/mahjong_ranking/player_ladder_score.html:51
msgid "Season"
msgstr "Saison"
@@ -387,5 +364,24 @@ msgstr "Hanchans welche in der Ladder zählen"
msgid "Go"
msgstr "Los"
#: views.py:149 views.py:166
msgid "Event does not exist"
msgstr "Veranstaltung existiert nicht"
#: views.py:207
msgid "Season does not exist"
msgstr "Saison existiert nicht"
#: views.py:300
#, python-format
msgid "No user found matching the name %s"
msgstr "Kein Benutzer mit dem Namen %s gefunden"
#~ msgid "Edit"
#~ msgstr "Bearbeiten"
#~ msgid "Add"
#~ msgstr "Hinzufügen"
#~ msgid "Tournament Hanchans"
#~ msgstr "Turnierwertungen"

View File

@@ -1,143 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
('events', '__first__'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='EventRanking',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('placement', models.PositiveIntegerField(null=True, blank=True)),
('avg_placement', models.FloatField(default=4)),
('avg_score', models.FloatField(default=0)),
('hanchan_count', models.PositiveIntegerField(default=0)),
('good_hanchans', models.PositiveIntegerField(default=0)),
('won_hanchans', models.PositiveIntegerField(default=0)),
('dirty', models.BooleanField(default=True, editable=False)),
('event', models.ForeignKey(to='events.Event')),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ('placement', 'avg_placement', '-avg_score'),
},
),
migrations.CreateModel(
name='Hanchan',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('comment', models.TextField(verbose_name='Anmerkung', blank=True)),
('confirmed', models.BooleanField(default=True, help_text='Nur g\xfcltige und best\xe4tigte Hanchans kommen in die Wertung.', verbose_name='Wurde best\xe4tigt')),
('player_names', models.CharField(max_length=127, editable=False)),
('start', models.DateTimeField(help_text='Wichtig damit die richtigen Hanchans in die Wertung kommen.', verbose_name='Beginn')),
('valid', models.BooleanField(default=False, verbose_name='Ist g\xfcltig')),
('event', models.ForeignKey(to='events.Event')),
],
options={
'ordering': ('-start',),
'verbose_name': 'Hanchan',
'verbose_name_plural': 'Hanchans',
},
),
migrations.CreateModel(
name='KyuDanRanking',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('dan', models.PositiveSmallIntegerField(null=True, blank=True)),
('dan_points', models.PositiveIntegerField(default=0)),
('kyu', models.PositiveSmallIntegerField(default=10, null=True, blank=True)),
('kyu_points', models.PositiveIntegerField(default=0)),
('won_hanchans', models.PositiveIntegerField(default=0)),
('good_hanchans', models.PositiveIntegerField(default=0)),
('hanchan_count', models.PositiveIntegerField(default=0)),
('dirty', models.BooleanField(default=True, editable=False)),
('user', models.OneToOneField(to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ('-dan_points', '-kyu_points'),
'verbose_name': 'Ky\u016b/Dan Wertung',
'verbose_name_plural': 'Ky\u016b/Dan Wertungen',
},
),
migrations.CreateModel(
name='LadderRanking',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('placement', models.PositiveIntegerField(null=True, blank=True)),
('avg_placement', models.FloatField(null=True, blank=True)),
('avg_score', models.FloatField(null=True, blank=True)),
('hanchan_count', models.PositiveIntegerField(default=0)),
('good_hanchans', models.PositiveIntegerField(default=0)),
('won_hanchans', models.PositiveIntegerField(default=0)),
('dirty', models.BooleanField(default=True, editable=False)),
],
options={
'ordering': ('placement', 'avg_placement', '-avg_score'),
},
),
migrations.CreateModel(
name='LadderSeason',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=100)),
('start', models.DateField()),
('end', models.DateField()),
('dirty', models.BooleanField(default=True, editable=False)),
],
options={
'ordering': ('start',),
'verbose_name': 'Saison',
'verbose_name_plural': 'Saisons',
},
),
migrations.CreateModel(
name='Player',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('score', models.PositiveIntegerField(default=0)),
('placement', models.PositiveSmallIntegerField(default=None, null=True, blank=True)),
('kyu_points', models.PositiveSmallIntegerField(default=None, null=True, blank=True)),
('dan_points', models.PositiveSmallIntegerField(default=None, null=True, blank=True)),
('bonus_points', models.PositiveSmallIntegerField(default=0, null=True, blank=True)),
('comment', models.TextField(verbose_name='Anmerkung', blank=True)),
('hanchan', models.ForeignKey(to='mahjong_ranking.Hanchan')),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['-score'],
},
),
migrations.AddField(
model_name='ladderranking',
name='season',
field=models.ForeignKey(to='mahjong_ranking.LadderSeason'),
),
migrations.AddField(
model_name='ladderranking',
name='user',
field=models.ForeignKey(to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='hanchan',
name='players',
field=models.ManyToManyField(to=settings.AUTH_USER_MODEL, verbose_name='Spieler', through='mahjong_ranking.Player'),
),
migrations.AddField(
model_name='hanchan',
name='season',
field=models.ForeignKey(blank=True, editable=False, to='mahjong_ranking.LadderSeason', null=True),
),
migrations.AlterUniqueTogether(
name='player',
unique_together=set([('hanchan', 'user')]),
),
]

View File

@@ -1,5 +1,7 @@
# -*- encoding: utf-8 -*-
# TODO: Rankings archiv Flag erstellen, womit sie nicht mehr neuberechnet werden dürfen.
from datetime import date, timedelta
from django.conf import settings
@@ -33,7 +35,6 @@ class EventRanking(models.Model):
hanchan_count = models.PositiveIntegerField(default=0)
good_hanchans = models.PositiveIntegerField(default=0)
won_hanchans = models.PositiveIntegerField(default=0)
dirty = models.BooleanField(default=True, editable=False)
class Meta(object):
ordering = ('placement', 'avg_placement', '-avg_score',)
@@ -48,10 +49,6 @@ class EventRanking(models.Model):
Diese Daten werden benötigt um die Platzierung zu erstellen. Sie
können zwar sehr leicht errechnet werden, es macht trotzdem Sinn
sie zwischen zu speichern.
Das Eigenschaft dirty ist ein altes Überbleibsel, um das Objekt
zur neuberrechnung zu markieren. Mittlerweile wird ein lokaler
Cache dafür verwendet, das ist schneller.
"""
logger.info(u'Recalculate EventRanking for Player %s in %s', self.user,
self.event.name) # @IgnorePep8
@@ -59,14 +56,13 @@ class EventRanking(models.Model):
event=self.event_id) # @IgnorePep8
aggregator = event_hanchans.aggregate(
models.Avg('placement'),
models.Avg('score'),
models.Avg('game_score'),
models.Count('pk'))
self.avg_placement = aggregator['placement__avg']
self.avg_score = aggregator['score__avg']
self.hanchan_count = aggregator['pk__count']
self.good_hanchans = event_hanchans.filter(placement__lt=3).count()
self.won_hanchans = event_hanchans.filter(placement=1).count()
self.dirty = False
if self.hanchan_count <= 0:
self.delete()
else:
@@ -80,20 +76,16 @@ class Hanchan(models.Model):
Außerdem gehört jede Hanchan zu einer Veranstaltung.
"""
comment = models.TextField(_('Comment'), blank=True)
confirmed = models.BooleanField(_('Has been Confirmed'), default=True,
help_text=_(
'Only valid and confirmed Hanchans will be counted in the rating.')) # @IgnorePep8
confirmed = models.BooleanField(_('Has been Confirmed'), default=True, help_text=_('Only valid and confirmed Hanchans will be counted in the rating.')) # @IgnorePep8
event = models.ForeignKey(Event)
player_names = models.CharField(max_length=127, editable=False)
player_names = models.CharField(max_length=255, editable=False)
players = models.ManyToManyField(
settings.AUTH_USER_MODEL,
through='Player',
verbose_name=_('Players')
)
season = models.ForeignKey('LadderSeason', blank=True, null=True,
editable=False) # @IgnorePep8
start = models.DateTimeField(_('Start'), help_text=_(
'This is crucial to get the right Hanchans that scores')) # @IgnorePep8
season = models.ForeignKey('LadderSeason', blank=True, null=True, editable=False)
start = models.DateTimeField(_('Start'), help_text=_('This is crucial to get the right Hanchans that scores'))
valid = models.BooleanField(_('Is Valid'), default=False)
class Meta(object):
@@ -122,22 +114,26 @@ class Hanchan(models.Model):
self.valid = False
return _('For a Hanchan exactly 4 players are needed.')
score_sum = self.player_set.aggregate(Sum('score'))['score__sum']
score_sum = self.player_set.aggregate(Sum('input_score'))['input_score__sum']
if score_sum == 100000:
self.valid = True
return '4 Spieler, 100.000 Endpunktestand, die Hanchan ist \
korrekt!'
elif score_sum > 100000 and self.player_set.filter(score=0):
self.valid = True
return 'Endpunktestand über 100.000, aber jemand ist auf 0 \
gefallen. Die Hanchan stimmt.'
# elif score_sum > 100000 and self.player_set.filter(score=0):
# self.valid = True
# return 'Endpunktestand über 100.000, aber jemand ist auf 0 \
# gefallen. Die Hanchan stimmt.'
elif score_sum < 100000:
self.valid = False
return 'Endpunktestand weniger als 100.000 Punkte.'
elif score_sum > 100000 and not self.player_set.filter(score=0):
elif score_sum > 100000:
self.valid = False
return 'Endpunktestand über 100.000, aber niemand ist auf 0 \
gefallen.'
return 'Endpunktestand mehr als 100.000 Punkte.'
#elif score_sum > 100000 and not self.player_set.filter(score=0):
# self.valid = False
# return 'Endpunktestand über 100.000, aber niemand ist auf 0 \
# gefallen.'
else:
self.valid = False
return 'Wir wissen nicht warum, aber das kann nicht passen...'
@@ -177,7 +173,7 @@ class Hanchan(models.Model):
"""
logger.debug("Berechne die Platzierungen neu...")
attending_players = self.player_set.select_related('hanchan', 'user')
attending_players = attending_players.order_by('-score')
attending_players = attending_players.order_by('-game_score')
other_player_placement = 0
other_player_score = 0
placement = 1
@@ -185,15 +181,15 @@ class Hanchan(models.Model):
logger.info("Compute player pacements for Hanchan Nr. %d", self.pk)
for player in attending_players:
player_list.append(player.user.username)
if player.score <= 0:
if player.game_score <= 0:
player.placement = 4
elif player.score == other_player_score:
elif player.game_score == other_player_score:
player.placement = other_player_placement
else:
player.placement = placement
placement += 1
other_player_placement = player.placement
other_player_score = player.score
other_player_score = player.game_score
player.save(season_id=self.season_id, mark_dirty=True)
def get_absolute_url(self):
@@ -206,21 +202,20 @@ class Hanchan(models.Model):
def save(self, **kwargs):
logger.debug("Hanchan save() wurde getriggert!")
self.season = self.season or LadderSeason.objects.get_by_date(
self.start)
self.season = self.season or LadderSeason.objects.get_by_date(self.start)
if self.pk:
self.check_validity()
self.compute_player_placements()
self.player_names = ', '.join(self.player_set.values_list(
'user__username', flat=True).order_by('-score'))
'user__username', flat=True).order_by('-input_score'))
return models.Model.save(self, **kwargs)
class KyuDanRanking(models.Model):
u"""
Die Einstufung des Spieles im Kyu bzw. Dan System.
Die Einstufung des Spielers im Kyu bzw. Dan System.
Im Gegensatz zum Ladder Ranking ist das nicht Saison gebunden.
daher läuft es getrennt.
Deswegen läuft es getrennt.
"""
user = models.OneToOneField(settings.AUTH_USER_MODEL)
dan = models.PositiveSmallIntegerField(blank=True, null=True)
@@ -230,8 +225,10 @@ class KyuDanRanking(models.Model):
won_hanchans = models.PositiveIntegerField(default=0)
good_hanchans = models.PositiveIntegerField(default=0)
hanchan_count = models.PositiveIntegerField(default=0)
dirty = models.BooleanField(default=True, editable=False)
wins_in_a_row = 0
legacy_date = models.DateField(blank=True, null=True)
legacy_dan_points = models.PositiveIntegerField(default=0)
legacy_kyu_points = models.PositiveIntegerField(default=0)
class Meta(object):
ordering = ('-dan_points', '-kyu_points',)
@@ -239,10 +236,10 @@ class KyuDanRanking(models.Model):
verbose_name_plural = _(u'Kyū/Dan Rankings')
def __unicode__(self):
if self.dan_points:
return u"%s - %d. Dan" % (self.user.username, self.dan)
if self.dan_points is not None:
return u"%s - %d. Dan" % (self.user.username, self.dan or 1)
else:
return u"%s - %d. Kyu" % (self.user.username, self.kyu)
return u"%s - %d. Kyu" % (self.user.username, self.kyu or 10)
def append_3_in_a_row_bonuspoints(self, hanchan):
u"""
@@ -312,7 +309,7 @@ class KyuDanRanking(models.Model):
self.kyu_points += bonus_points
def get_absolute_url(self):
if self.dan:
if self.dan or self.dan_points > 0:
return reverse('player-dan-score', args=[self.user.username])
else:
return reverse('player-kyu-score', args=[self.user.username])
@@ -324,80 +321,90 @@ class KyuDanRanking(models.Model):
"""
logger.debug("recalculating Kyu/Dan punkte for %s...", self.user)
valid_hanchans = Player.objects.valid_hanchans(user=self.user_id)
if self.legacy_date:
valid_hanchans = valid_hanchans.filter(hanchan__start__gt=self.legacy_date)
valid_hanchans = valid_hanchans.order_by('hanchan__start')
self.kyu_points = 0
self.dan_points = 0
self.kyu_points = self.legacy_kyu_points or 0
self.dan_points = self.legacy_dan_points or 0
self.dan = None
self.kyu = 10
self.update_rank()
self.hanchan_count = valid_hanchans.count()
self.won_hanchans = valid_hanchans.filter(placement=1).count()
self.good_hanchans = valid_hanchans.filter(placement=2).count()
logger.info("Neuberechnung der Punkte von %s", self.user)
for hanchan in valid_hanchans:
self.update_points(hanchan)
self.append_tournament_bonuspoints(hanchan)
for played_hanchan in valid_hanchans:
self.update_hanchan_points(played_hanchan)
self.append_tournament_bonuspoints(played_hanchan)
self.update_rank()
self.append_3_in_a_row_bonuspoints(hanchan)
self.append_3_in_a_row_bonuspoints(played_hanchan)
self.update_rank()
hanchan.save(force_update=True, mark_dirty=False)
played_hanchan.save(force_update=True, mark_dirty=False)
self.save(force_update=True)
def update_points(self, player):
def update_hanchan_points(self, played_hanchan):
"""
Berechne die Kyu bzw. Dan Punkte für ein Spiel neu.
:param player: Das Player Objekt das neuberechnet werden soll.
Berechne die Kyu bzw. Dan Punkte für eine Hanchan neu.
Für Turniere gelten andere Regeln zur Punktevergabe:
1. Platz 4 Punkte
2. Platz 3 Punkte
3. Platz 2 Punkte
4. Platz 1 Punkt
:param played_hanchan: Das Player Objekt das neuberechnet werden soll.
"""
player.bonus_points = 0
player.comment = ""
player.dan_points = None
player.kyu_points = None
if player.hanchan.event.is_tournament:
tourney_points = 4 - player.placement
played_hanchan.bonus_points = 0
played_hanchan.comment = ""
played_hanchan.dan_points = None
played_hanchan.kyu_points = None
print self.user, played_hanchan.input_score, played_hanchan.game_score
if played_hanchan.hanchan.event.is_tournament:
tourney_points = 4 - played_hanchan.placement
if self.dan:
player.dan_points = tourney_points
played_hanchan.dan_points = tourney_points
else:
player.kyu_points = tourney_points
played_hanchan.kyu_points = tourney_points
elif self.dan:
if player.score >= 60000:
player.dan_points = 3
elif player.score == 0:
player.dan_points = -3
elif player.placement == 1:
player.dan_points = 2
elif player.placement == 2:
player.dan_points = 1
elif player.placement == 3:
player.dan_points = -1
elif player.placement == 4:
player.dan_points = -2
elif player.score >= 60000:
player.kyu_points = 3
elif player.score >= 30000:
player.kyu_points = 1
elif player.score < 10000:
player.kyu_points = -1
if played_hanchan.game_score >= 60000:
played_hanchan.dan_points = 3
elif played_hanchan.game_score == 0:
played_hanchan.dan_points = -3
elif played_hanchan.placement == 1:
played_hanchan.dan_points = 2
elif played_hanchan.placement == 2:
played_hanchan.dan_points = 1
elif played_hanchan.placement == 3:
played_hanchan.dan_points = -1
elif played_hanchan.placement == 4:
played_hanchan.dan_points = -2
#Kein Turnier, Spieler nicht im Dan, dann muss er Sie Kyu Punkte bekommen
elif played_hanchan.game_score >= 60000:
played_hanchan.kyu_points = 3
elif played_hanchan.game_score >= 30000:
played_hanchan.kyu_points = 1
elif played_hanchan.game_score < 10000:
played_hanchan.kyu_points = -1
else:
player.kyu_points = 0
played_hanchan.kyu_points = 0
# Add the hanchans points to the players score
if player.dan_points:
if self.dan_points + player.dan_points < 0:
# Add the hanchans points to the players points
if self.dan:
if self.dan_points + played_hanchan.dan_points < 0:
# Only substract so much points that player has 0 Points:
player.dan_points -= (self.dan_points + player.dan_points)
self.dan_points += player.dan_points
elif player.kyu_points:
if self.kyu_points + player.kyu_points < 0:
played_hanchan.dan_points -= (self.dan_points + played_hanchan.dan_points)
self.dan_points += played_hanchan.dan_points
print "Danpunkte des Spielers: {}, Danpunkte der Hanchan {}".format(self.dan_points, played_hanchan.dan_points)
else:
if self.kyu_points + played_hanchan.kyu_points < 0:
# Only substract so much points that player has 0 Points:
player.kyu_points -= (self.kyu_points + player.kyu_points)
self.kyu_points += player.kyu_points
played_hanchan.kyu_points -= (self.kyu_points + played_hanchan.kyu_points)
self.kyu_points += played_hanchan.kyu_points
def update_rank(self):
if self.dan and self.dan_points < 0:
self.dan_points = 0
self.dan = 1
elif self.dan:
elif self.dan or self.dan_points > 0:
old_dan = self.dan
for min_points, dan_rank in DAN_RANKS:
if self.dan_points > min_points:
@@ -429,7 +436,6 @@ class LadderRanking(models.Model):
hanchan_count = models.PositiveIntegerField(default=0)
good_hanchans = models.PositiveIntegerField(default=0)
won_hanchans = models.PositiveIntegerField(default=0)
dirty = models.BooleanField(default=True, editable=False)
class Meta(object):
ordering = ('placement', 'avg_placement', '-avg_score',)
@@ -443,15 +449,14 @@ class LadderRanking(models.Model):
ladder_hanchans = Player.objects.ladder_hanchans(
self.user_id, self.season_id)
aggregate = ladder_hanchans.aggregate(
models.Avg('placement'),
models.Avg('score'),
models.Count('pk')
avg_placement = models.Avg('placement'),
avg_score = models.Avg('game_score'),
hanchan_count = models.Count('pk')
)
self.dirty = False
self.placement = None
self.hanchan_count = aggregate['pk__count']
self.avg_placement = aggregate['placement__avg']
self.avg_score = aggregate['score__avg']
self.hanchan_count = aggregate['hanchan_count']
self.avg_placement = aggregate['avg_placement']
self.avg_score = aggregate['avg_score']
self.good_hanchans = ladder_hanchans.filter(placement=2).count()
self.won_hanchans = ladder_hanchans.filter(placement=1).count()
self.save(force_update=True)
@@ -464,12 +469,12 @@ class LadderSeasonManager(models.Manager):
"""
current_season = cache.get('current_mahjong_season')
if not current_season:
try:
today = date.today()
current_season = self.filter(start__lte=today, end__gte=today)
current_season = current_season[0]
except IndexError:
current_season = None
current_year = date.today().year
current_season = self.get_or_create(name=current_year, defaults={
'name': current_year,
'start': date(year=current_year,month=1, day=1),
'end': date(year=current_year, month=12, day=31)
})[0]
cache.set('current_mahjong_season', current_season, 4320)
return current_season
@@ -489,11 +494,10 @@ class LadderSeason(models.Model):
u"""
Eine Saison für das Kasu interne Ladder-Ranking.
"""
name = models.CharField(max_length=100)
name = models.PositiveSmallIntegerField()
start = models.DateField()
end = models.DateField()
objects = LadderSeasonManager()
dirty = models.BooleanField(default=True, editable=False)
class Meta(object):
ordering = ('start',)
@@ -501,7 +505,7 @@ class LadderSeason(models.Model):
verbose_name_plural = _('Ladder Seasons')
def __unicode__(self):
return self.name
return str(self.name)
def get_absolute_url(self):
"""
@@ -526,7 +530,6 @@ class LadderSeason(models.Model):
ranking.placement = placement
ranking.save(force_update=True)
placement += 1
self.dirty = False
self.save(force_update=True)
@@ -544,7 +547,7 @@ class PlayerManager(models.Manager):
return queryset
def ladder_hanchans(self, user=None, season=None, num_hanchans=None,
max_age=None): # @IgnorePep8
max_age=None):
queryset = self.valid_hanchans(user).order_by('-hanchan__start')
queryset = queryset.select_related()
season = season or LadderSeason.objects.current()
@@ -589,18 +592,19 @@ class PlayerManager(models.Manager):
class Player(models.Model):
hanchan = models.ForeignKey(Hanchan)
user = models.ForeignKey(settings.AUTH_USER_MODEL)
score = models.PositiveIntegerField(default=0)
input_score = models.IntegerField(default=0)
game_score = models.PositiveIntegerField(default=0)
placement = models.PositiveSmallIntegerField(
blank=True,
null=True,
default=None
)
kyu_points = models.PositiveSmallIntegerField(
kyu_points = models.SmallIntegerField(
blank=True,
null=True,
default=None
)
dan_points = models.PositiveSmallIntegerField(
dan_points = models.SmallIntegerField(
blank=True,
null=True,
default=None
@@ -615,13 +619,14 @@ class Player(models.Model):
class Meta(object):
unique_together = ('hanchan', 'user')
ordering = ['-score']
ordering = ['-input_score']
def __str__(self):
return "{0}'s Punkte vom {1: %d.%m.%Y um %H:%M}".format(
self.user.username, self.hanchan.start)
def save(self, mark_dirty=True, season_id=None, *args, **kwargs):
self.game_score = self.input_score if self.input_score > 0 else 0
season_id = season_id or self.hanchan.season_id
super(Player, self).save(*args, **kwargs)
@@ -634,7 +639,7 @@ class Player(models.Model):
if season_id:
logger.debug(
"Marking %s's season no. %i ranking for recalculation.",
self.user, season_id) # @IgnorePep8
self.user, season_id)
set_dirty(season=season_id, user=self.user_id)
logger.debug("Marking season no %i for recalculation.", season_id)
set_dirty(season=season_id)

View File

@@ -9,11 +9,11 @@
{% for hanchan in hanchan_list %}
<div class="grid_12" id="{{ hanchan.pk }}"><h3>{{hanchan.start|time:'H:i'}}: {{ hanchan.player_names }}</h3></div>
{% for player in hanchan.player_set.all %}
<a class="grid_1" href="{% url 'player-ladder-score' player.user %}"><img src="{% if player.user.get_profile.thumbnail %}{{player.user.get_profile.thumbnail.url}}{% else %}{{STATIC_URL}}img/unknown_thumbnail.png{% endif %}" class="avatar" alt="{{ player.user }}" title="{{ player.user }}"/></a>
<a class="grid_1" href="{% url 'player-ladder-score' player.user %}"><img src="{% if player.user.avatar %}{{player.user.thumbnail.url}}{% else %}{{STATIC_URL}}img/unknown_thumbnail.png{% endif %}" class="avatar" alt="{{ player.user }}" title="{{ player.user }}"/></a>
<div class="grid_2">
<a class="player" href="{% url 'player-ladder-score' player.user %}" title="{{ player.comment }}">{{ player.user }}</a>
<p><strong>{{ player.placement|ordinal }} {% trans 'Place' %}</strong><br />
<strong>{% trans 'Score' %}:</strong> {{ player.score|intcomma }}<br />
<strong>{% trans 'Score' %}:</strong> {{ player.game_score|intcomma }}<br />
{% if player.dan_points != None %}
<strong>{% trans 'Dan Points' %}:</strong> {{ player.dan_points }}
{% else %}

View File

@@ -15,7 +15,7 @@
<th rowspan="2">{% trans "Nickname" %}</th>
<th rowspan="2">{% trans "Name" %}</th>
<th colspan="2">{% trans 'Average' %}</th>
<th colspan="3">Hanchans</th>
<th colspan="3">{% trans 'Hanchans' %}</th>
</tr>
<tr>
<th>{% trans 'Placement' %}</th>
@@ -26,54 +26,33 @@
</tr>
</thead>
{% for player in eventranking_list %}
{% with player.user.get_profile as profile %}
<tr>
<td class="center">{{player.placement}}.</td>
<td class="avatar"><a href="{{ player.user.get_absolute_url }}">
{% if profile.thumbnail %}
<img src="{{profile.thumbnail.url}}" alt="" />
{% else %}
<img src="{{STATIC_URL}}img/unknown_thumbnail.png" alt=""/>
{% endif %}
</a></td>
<td><a href="{{ player.user.get_absolute_url }}">{{player.user}}</a></td>
<td>{% if user.is_authenticated %}{{profile.last_name}} {{profile.first_name}}{% else %} ---{% endif %}</td>
<td class="center">{{player.avg_placement|floatformat:2 }}</td>
<td class="right">{{player.avg_score|floatformat:0 }}</td>
<td class="center">{{player.placement}}.</td>
<td class="avatar"><a href="{{ player.user.get_absolute_url }}">
{% if player.user.avatar %}
<img src="{{player.user.thumbnail.url}}" alt="" />
{% else %}
<img src="{{STATIC_URL}}img/unknown_thumbnail.png" alt=""/>
{% endif %}
</a></td>
<td><a href="{{ player.user.get_absolute_url }}">{{player.user}}</a></td>
<td>{% if user.is_authenticated %}{{player.user.last_name}} {{player.user.first_name}}{% else %}---{% endif %}</td>
<td class="center">{{player.avg_placement|floatformat:2 }}</td>
<td class="right">{{player.avg_score|floatformat:0 }}</td>
<td class="right">{{player.hanchan_count}}</td>
<td class="right">{{player.good_hanchans}}</td>
<td class="right">{{player.won_hanchans}}</td>
<td class="right">{{player.won_hanchans}}</td>
</tr>
{% endwith %}
{% empty %}
<tr><td colspan="8">Leider hat es noch niemand in das Ranking geschafft.
Ein Spieler wird erst ins Ranking genommen wenn er 5 Hanchans absolviert hat.</td></tr>
<tr><td colspan="9">Leider hat es noch niemand in das Ranking geschafft.</td></tr>
{% endfor %}
</table>
</div>
{% endblock %}
{% block sidebar %}
{% if is_archive %}
<h2>{% trans 'Ladder Archive' %}</h2>
<ul class="list">
{% for season in season_archive %}
<li class="season"><a href="{% url 'mahjong-ladder-archive' season.id %}">{{season.name}}</a></li>
{% endfor %}
</ul>
{% else %}
<h2>{% trans 'Latest Events' %}</h2>
<ul class="list">
{% for event in latest_event_list %}
<li class="event"><a href="{% url 'event-hanchan-list' event.pk %}">{{event.name}}</a></li>
{% endfor %}
</ul>
<h2>{% trans 'Latest Hanchans' %}</h2>
<ul class="comment_list">
{% for hanchan in latest_hanchan_list %}
<li class="hanchan"><a href="{% url 'event-hanchan-list' hanchan.event.pk %}">{{hanchan.event.name}}</a> {{hanchan.start|time:'H:i'}}: {{hanchan.player_names}}</li>
{% endfor %}
</ul>
{% endif %}
{% block buttonbar %}
{% if perms.mahjong_ranking.add_hanchan %}
<a class="button" href="{{event.get_edit_url}}"><span class="fa fa-pencil"></span> {% trans 'Edit Event' %}</a>
<a class="button" href="{% url 'add-hanchan-form' event.id %}"><span class="fa fa-plus-circle"></span> {% trans 'Add Hanchan' %}</a>
{% endif %}
{% endblock %}

View File

@@ -9,6 +9,9 @@
<fieldset>
<legend>{% trans "Delete Hanchan" %}</legend>
{% include 'form.html' %}
<div class="grid_2 fa fa-exclamation-triangle fa-5x" ></div>
<p class="grid_6">Bist du sicher dass du diese Hanchan und alle Ergebnisse und Wertungen welche sich hierauf beziehen löschen möchtest?</p>
<br class="clear">
<p class="buttonbar">
<button type="button" onclick="window.history.back()"><span class="fa fa-close"></span> {% trans 'Cancel' %}</button>
<button type="submit"><span class="fa fa-trash"></span> {% trans 'Delete' %}</button>

View File

@@ -1,59 +1,52 @@
{% extends "events/event_detail.html" %}
{% load i18n comments fieldset_extras %}
{% block title %}
{% if hanchan.id %}{% trans "Edit Hanchan" %}{% else %}{% trans "Add Hanchan" %}{% endif %}
{% endblock %}
{% block title %}{% if hanchan.id %}{% trans "Edit Hanchan" %}{% else %}{% trans "Add Hanchan" %}{% endif %}{% endblock %}
{% block maincontent %}
{% get_fieldset "event, start" from form as event_formset %}
{% if perms.mahjong_ranking.delete_hanchan %}
{% get_fieldset "comment, confirmed" from form as hanchan_formset %}
{% else %}
{% get_fieldset "comment" from form as hanchan_formset %}
{% endif %}
{% for hidden in form.hidden_fields %}{% if hidden.errors %}{{ hidden.errors }}{% endif %}{% endfor %}
{% get_fieldset "event, start" from form as event_formset %}
{% if perms.mahjong_ranking.delete_hanchan %}
{% get_fieldset "comment, confirmed" from form as hanchan_formset %}
{% else %}
{% get_fieldset "comment" from form as hanchan_formset %}
{% endif %}
{% for hidden in form.hidden_fields %}{% if hidden.errors %}{{ hidden.errors }}{% endif %}{% endfor %}
<form class="grid_12" method="post">
{% csrf_token %}
<fieldset>
<legend>{% if hanchan.id %}{% trans "Edit Hanchan" %}{% else %} {% trans "Add Hanchan" %}{% endif %}</legend>
{% with event_formset as form %}{% include "form.html" %}{% endwith %}
<div>
<label class="field_name required">{% trans 'Players' %}</label>
{{ formset.management_form }}
<table>
<tr>
<th>{% trans 'User' %}</th>
<th>{% trans 'Score' %}</th>
<th>{% trans 'Bonus' %}</th>
<th width="75%">{% trans 'Comment' %}</th>
</tr>
{% for form in formset %}
<tr>
<td class="{{form.user.css_classes}}">{{form.id}} {{form.user}} {% for error in form.user.errors %}<br />{{error}}{% endfor %}</td>
<td class="{{form.score.css_classes}}">{{form.score}} {% for error in form.score.errors %}<br />{{error}}{% endfor %}</td>
<td class="{{form.bonus_points.css_classes}}">{{form.bonus_points}} {% for error in form.bonus_points.errors %}<br />{{error}}{% endfor %}</td>
<td class="{{form.comment.css_classes}}" width="*">{{form.comment}} {% for error in form.comment.errors %}<br />{{error}}{% endfor %}</td>
</tr>
{% endfor %}
</table>
</div>
{% for error in formset.errors %}<p class="error">{{error}}</p>{% endfor %}
{% if hanchan.pk and not hanchan.valid %}<p class="error">{{hanchan.check_validity}}</p>{% endif %}
{% with hanchan_formset as form %}{% include "form.html" %}{% endwith %}
{% for error in form.non_field_errors %}<p class="error">{{error}}</p>{% endfor %}
<p class="buttonbar">
<a href="{% url 'event-hanchan-list' event.pk %}" class="button"><span class="fa fa-undo"></span> {% trans 'back' %}</a>
<button type="submit"><span class="fa fa-hdd-o"></span> {% trans 'save' %}</button>
</p>
</fieldset>
</form>
<form class="grid_12" method="post"><fieldset>
{% csrf_token %}
<legend>{% if hanchan.id %}{% trans "Edit Hanchan" %}{% else %} {% trans "Add Hanchan" %}{% endif %}</legend>
{% with event_formset as form %}{% include "form.html" %}{% endwith %}
<div>
<label class="field_name required">{% trans 'Players' %}</label>
{{ formset.management_form }}
<table>
<tr>
<th>{% trans 'User' %}</th>
<th>{% trans 'Score' %}</th>
<th>{% trans 'Bonus' %}</th>
<th width="75%">{% trans 'Comment' %}</th>
</tr>
{% for form in formset %}
<tr>
<td class="{{form.user.css_classes}}">{{form.id}} {{form.user}} {% for error in form.user.errors %}<br />{{error}}{% endfor %}</td>
<td class="{{form.input_score.css_classes}}">{{form.input_score}} {% for error in form.input_score.errors %}<br />{{error}}{% endfor %}</td>
<td class="{{form.bonus_points.css_classes}}">{{form.bonus_points}} {% for error in form.bonus_points.errors %}<br />{{error}}{% endfor %}</td>
<td class="{{form.comment.css_classes}}" width="*">{{form.comment}} {% for error in form.comment.errors %}<br />{{error}}{% endfor %}</td>
</tr>
{% endfor %}
</table>
</div>
{{ formset.non_form_errors }}
{% if hanchan.pk and not hanchan.valid %}<p class="error">{{hanchan.check_validity}}</p>{% endif %}
{% with hanchan_formset as form %}
{% for error in form.non_field_errors %}<p class="error">{{error}}</p>{% endfor %}
{% include "form.html" %}
{% endwith %}
<p class="buttonbar">
<a href="{% url 'event-hanchan-list' event.pk %}" class="button"><span class="fa fa-undo"></span> {% trans 'back' %}</a>
<button type="submit"><span class="fa fa-hdd-o"></span> {% trans 'save' %}</button>
</p>
</fieldset></form>
{% endblock %}
{% block buttonbar %}{% endblock %}

View File

@@ -38,22 +38,22 @@
</tr>
</thead>
<tbody>
{% for ranking in kyudanranking_list %}{% with ranking.user.get_profile as profile %}
{% for ranking in kyudanranking_list %}
<tr>
<td>
{% if profile.thumbnail %}
<a href="{{ ranking.get_absolute_url }}"><img src="{{profile.thumbnail.url}}" alt="" /></a>
{% if ranking.user.avatar %}
<a href="{{ ranking.get_absolute_url }}"><img src="{{ranking.user.thumbnail.url}}" alt="" /></a>
{% else %}
<a href="{{ ranking.get_absolute_url }}"><img src="{{STATIC_URL}}img/unknown_thumbnail.png" alt=""/></a>
{% endif %}
</td>
<td><a href="{{ ranking.get_absolute_url }}">{{ ranking.user }}</a></td>
<td>{% if user.is_authenticated %}{{profile.last_name}} {{profile.first_name}}{% else %} ---{% endif %}</td>
<td>{% if user.is_authenticated %}{{ranking.user.last_name}} {{ranking.user.first_name}}{% else %}---{% endif %}</td>
<td>{% if ranking.dan %} {{ranking.dan}}. Dan {% else %} {{ranking.kyu}} Kyu {% endif %}</td>
<td class="right">{% if ranking.dan %} {{ranking.dan_points}} {% else %} {{ranking.kyu_points}} {% endif %}</td>
<td class="right">{{ranking.hanchan_count}}</td>
</tr>
{% endwith %}{% endfor %}
{% endfor %}
</tbody>
</table>
</main>

View File

@@ -33,19 +33,17 @@
</tr>
</thead>
{% for player in ladderranking_list %}
{% with player.user.get_profile as profile %}
<tr>
<td class="center">{{player.placement}}.</td>
<td><a href="{{ player.get_absolute_url }}?season={{season.id}}"><img src="{% if profile.thumbnail %}{{profile.thumbnail.url}}{% else %}{{STATIC_URL}}img/unknown_thumbnail.png{% endif %}" class="avatar" alt=""/></a></td>
<td><a href="{{ player.get_absolute_url }}?season={{season.id}}"><img src="{% if player.user.avatar %}{{player.user.thumbnail.url}}{% else %}{{STATIC_URL}}img/unknown_thumbnail.png{% endif %}" class="avatar" alt=""/></a></td>
<td><a href="{{ player.get_absolute_url }}?season={{season.id}}">{{player.user}}</a></td>
<td>{% if user.is_authenticated %}{{profile.last_name}} {{profile.first_name}}{% else %} ---{% endif %}</td>
<td>{% if user.is_authenticated %}{{player.user.last_name}} {{player.user.first_name}}{% else %}---{% endif %}</td>
<td class="center">{{player.avg_placement|floatformat:2 }}</td>
<td class="right">{{player.avg_score|floatformat:0 }}</td>
<td class="right">{{player.hanchan_count}}</td>
<td class="right">{{player.good_hanchans}}</td>
<td class="right">{{player.won_hanchans}}</td>
</tr>
{% endwith %}
{% empty %}
<tr>
<td colspan="9">Leider hat es noch niemand in das Ranking geschafft.

View File

@@ -35,7 +35,7 @@
<td class="center">{{result.placement}}.</td>
{% for player in result.hanchan.player_set.all %}
<td class="center"><a href="{% url 'player-dan-score' player.user.username %}">{{player.user}}</a><br/>
{{player.score }}
{{player.game_score }}
</td>
{% endfor %}
<td class="center">{{result.dan_points}}</td>

View File

@@ -24,7 +24,7 @@
<td><a href="{{ result.hanchan.get_absolute_url }}">{{ result.hanchan.event.name }}</a></td>
<td>{{ result.hanchan.start|time:'H:i' }}</td>
{% for player in result.hanchan.player_set.all %}
<td class="center"><a href="{% url 'player-invalid-score' player.user.username %}">{{player.user}}</a><br/> {{player.score }}</td>
<td class="center"><a href="{% url 'player-invalid-score' player.user.username %}">{{player.user}}</a><br/> {{player.input_score }}</td>
{% endfor %}
<td class="center">{{result.placement}}</td>
<td class="center">{{result.kyu_points}}</td>

View File

@@ -3,7 +3,7 @@
{% block title %} {% trans 'Kyu Score for' %} {{membership.username}} {% endblock %}
{% block teaser %}<h2>{% trans 'Kyu Score for' %}{{membership.username}}</h2>{% endblock %}
{% block teaser %}<h2>{% trans 'Kyu Score for' %} {{membership.username}}</h2>{% endblock %}
{% block score_list %}
<div class="grid_12">
@@ -34,7 +34,7 @@
<td>{{ result.hanchan.start|time:'H:i' }}</td>
<td class="center">{{result.placement}}.</td>
{% for player in result.hanchan.player_set.select_related %}
<td class="center"><a href="{% url 'player-kyu-score' player.user.username %}">{{player.user}}</a><br/> {{player.score }}</td>
<td class="center"><a href="{% url 'player-kyu-score' player.user.username %}">{{player.user}}</a><br/> {{player.game_score }}</td>
{% endfor %}
<td class="center">{{result.kyu_points}}</td>
<td>

View File

@@ -32,7 +32,7 @@
<td>{{ result.hanchan.start|time:'H:i' }}</td>
<td class="center">{{result.placement}}.</td>
{% for player in result.hanchan.player_set.select_related %}
<td class="center"><a href="{% url 'player-ladder-score' player.user.username %}?season={{season.id}}">{{player.user}}</a><br/> {{player.score}}</td>
<td class="center"><a href="{% url 'player-ladder-score' player.user.username %}?season={{season.id}}">{{player.user}}</a><br/> {{player.game_score}}</td>
{% endfor %}
<td>
{% if perms.mahjong_ranking.delete_hanchan %}

View File

@@ -13,30 +13,19 @@ import views
urlpatterns = patterns(
'',
url('^$', RedirectView.as_view(pattern_name='mahjong-ladder', permanent=True)),
url(r'players/$', views.KyuDanRankingList.as_view(),
name="kyudanranking-list"),
url(r'players/(?P<order_by>[\+\-\w]+)/$', views.KyuDanRankingList.as_view(),
name="kyudanranking-list"),
url(r'ranking/$', views.LadderRankingList.as_view(), name="mahjong-ladder"),
url(r'ranking/(?P<season>[\d]+)/$', views.LadderRankingList.as_view(),
name="mahjong-ladder"),
url(r'ranking/event/(?P<event>[\d]+)/$', views.EventHanchanList.as_view(),
name="event-hanchan-list"),
url(r'ranking/event/(?P<event>[\d]+)/ranking/$',
views.EventRankingList.as_view(), name="event-ranking"),
url(r'ranking/event/(?P<event>[\d]+)/add-hanchan/$',
views.HanchanForm.as_view(), name="add-hanchan-form"),
url(r'hanchan/(?P<hanchan>[\d]+)/edit/$', views.HanchanForm.as_view(),
name="edit-hanchan"),
url(r'hanchan/(?P<hanchan>[\d]+)/delete/$', views.DeleteHanchan.as_view(),
name="delete-hanchan"),
url(r'player/(?P<username>[\-\.\d\w]+)/dan/$',
views.PlayerDanScore.as_view(), name="player-dan-score"),
url(r'player/(?P<username>[\-\.\d\w]+)/invalid/$',
views.PlayerInvalidScore.as_view(), name="player-invalid-score"),
url(r'player/(?P<username>[\-\.\d\w]+)/kyu/$',
views.PlayerKyuScore.as_view(), name="player-kyu-score"),
url(r'player/(?P<username>[\-\.\d\w]+)/ladder/$',
views.PlayerLadderScore.as_view(), name="player-ladder-score"),
# url('^$', RedirectView.as_view(pattern_name='mahjong-ladder', permanent=True)),
url('^$',views.LadderRankingList.as_view()),
url(r'^event/(?P<event>[\d]+)/mahjong/$', views.EventHanchanList.as_view(), name="event-hanchan-list"),
url(r'^event/(?P<event>[\d]+)/add-hanchan/$', views.HanchanForm.as_view(), name="add-hanchan-form"),
url(r'^event/(?P<event>[\d]+)/mahjong-ranking/$', views.EventRankingList.as_view(), name="event-ranking"),
url(r'^hanchan/(?P<hanchan>[\d]+)/edit/$', views.HanchanForm.as_view(), name="edit-hanchan"),
url(r'^hanchan/(?P<hanchan>[\d]+)/delete/$', views.DeleteHanchan.as_view(), name="delete-hanchan"),
url(r'^mahjong-ladder/$', views.LadderRankingList.as_view(), name="mahjong-ladder"),
url(r'^mahjong-ladder/(?P<season>[\d]+)/$', views.LadderRankingList.as_view(), name="mahjong-ladder"),
url(r'^player/(?P<username>[\-\.\d\w]+)/dan/$', views.PlayerDanScore.as_view(), name="player-dan-score"),
url(r'^player/(?P<username>[\-\.\d\w]+)/invalid/$', views.PlayerInvalidScore.as_view(), name="player-invalid-score"),
url(r'^player/(?P<username>[\-\.\d\w]+)/kyu/$', views.PlayerKyuScore.as_view(), name="player-kyu-score"),
url(r'^player/(?P<username>[\-\.\d\w]+)/ladder/$', views.PlayerLadderScore.as_view(), name="player-ladder-score"),
url(r'^mahjong/$', views.KyuDanRankingList.as_view(), name="kyudanranking-list"),
url(r'^mahjong/(?P<order_by>[\+\-\w]+)/$', views.KyuDanRankingList.as_view(), name="kyudanranking-list"),
)

View File

@@ -136,6 +136,7 @@ class EventHanchanList(EventDetailMixin, generic.ListView):
Auflistung aller Hanchan die während der Veranstaltung gespielt wurden.
"""
model = models.Hanchan
template_name = 'mahjong_ranking/eventhanchan_list.html'
def get_queryset(self):
try: