Fehler bei Vergabe von Bonuspunkte korrigiert.
Kommentare für Bonuspunkte werden jetzt als Kommentar beim Spieler hinterlassen, nicht als Kommentar in der Hanchan. FIXED: 3_in_a_row counter wurde nicht zurückgesetzt wenn Bonuspunkte vergeben wurden. FIXED: Durchschnittliche Platzierung während eines Events wurde nur als Ganzzahl berechnet. Wird nun als Fießkomma berechnet und gesichert.
This commit is contained in:
@@ -24,7 +24,8 @@ def recalculate(modeladmin, request, queryset):
|
||||
set_dirty(user=kyu_dan_ranking.user_id)
|
||||
elif isinstance(modeladmin, SeasonRankingAdmin):
|
||||
for ladder_ranking in queryset:
|
||||
set_dirty(user=ladder_ranking.user_id, season=ladder_ranking.season)
|
||||
set_dirty(user=ladder_ranking.user_id,
|
||||
season=ladder_ranking.season)
|
||||
recalculate.short_description = _("Recalculate")
|
||||
|
||||
|
||||
@@ -41,6 +42,7 @@ def unconfirm(modeladmin, request, queryset):
|
||||
hanchan.save()
|
||||
unconfirm.short_description = _('Set unconfirmed')
|
||||
|
||||
|
||||
class EventRankingAdmin(admin.ModelAdmin):
|
||||
list_filter = ['event']
|
||||
list_display = ('placement', 'user', 'event', 'avg_placement', 'avg_score',
|
||||
@@ -61,7 +63,7 @@ class HanchanAdmin(admin.ModelAdmin):
|
||||
('Hanchan', {
|
||||
'fields': (
|
||||
('event', 'season'),
|
||||
'start',
|
||||
'start',
|
||||
('player1', 'player1_input_score', 'player1_comment'),
|
||||
('player2', 'player2_input_score', 'player2_comment'),
|
||||
('player3', 'player3_input_score', 'player3_comment'),
|
||||
@@ -84,7 +86,7 @@ class KyuDanAdmin(admin.ModelAdmin):
|
||||
'classes': ('grp-collapse grp-open',),
|
||||
}),
|
||||
('Frühere Aufzeichnungen', {
|
||||
'fields': ('legacy_date', ('legacy_kyu_points', 'legacy_dan_points')),
|
||||
'fields': ('legacy_date', 'legacy_hanchan_count', ('legacy_kyu_points', 'legacy_dan_points')),
|
||||
'classes': ('grp-collapse grp-closed',),
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -23,45 +23,33 @@ class HanchanForm(forms.ModelForm):
|
||||
|
||||
class Meta(object):
|
||||
model = models.Hanchan
|
||||
fields = ( 'start',
|
||||
'player1', 'player1_input_score',
|
||||
'player2', 'player2_input_score',
|
||||
'player3', 'player3_input_score',
|
||||
'player4', 'player4_input_score',
|
||||
fields = ('start',
|
||||
'player1', 'player1_input_score', # 'player1_comment',
|
||||
'player2', 'player2_input_score', # 'player2_comment',
|
||||
'player3', 'player3_input_score', # 'player3_comment',
|
||||
'player4', 'player4_input_score', # 'player4_comment',
|
||||
'comment')
|
||||
widgets = {'event': forms.HiddenInput(),
|
||||
'comment': forms.widgets.Textarea(attrs={'rows': 4, 'cols': 40})
|
||||
}
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(HanchanForm, self).__init__(*args, **kwargs)
|
||||
# self.fields['event'].widget.attrs['disabled'] = True
|
||||
for i in xrange(1, 4):
|
||||
self.fields['player%d_input_score' % i].widget.attrs['size'] = 6
|
||||
self.fields['player%d_input_score' % i].widget.attrs['type'] = 'number'
|
||||
player_input_score = 'player%d_input_score' % i
|
||||
self.fields[player_input_score].widget.attrs['size'] = 6
|
||||
self.fields[player_input_score].widget.attrs['type'] = 'number'
|
||||
|
||||
|
||||
'''
|
||||
def clean_start(self):
|
||||
u"""Das Datum darf nicht in der Zukunft liegen und es muss innerhalb
|
||||
der Dauer des Events liegen."""
|
||||
start = self.cleaned_data['start']
|
||||
event = self.cleaned_data['event']
|
||||
if start > timezone.now():
|
||||
raise django.forms.ValidationError(
|
||||
_("It's not allowed to enter future games."))
|
||||
if not event.start <= start <= event.end:
|
||||
raise django.forms.ValidationError(
|
||||
_("Only games running during this event are allowed."))
|
||||
return start
|
||||
'''
|
||||
|
||||
class HanchanAdminForm(HanchanForm):
|
||||
|
||||
class Meta(object):
|
||||
model = models.Hanchan
|
||||
fields = HanchanForm.Meta.fields + ('confirmed',)
|
||||
|
||||
|
||||
|
||||
class SeasonSelectForm(django.forms.Form):
|
||||
season = django.forms.ChoiceField(label='', choices=('a', 'b', 'c'))
|
||||
|
||||
|
||||
Binary file not shown.
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: kasu.mahjong_ranking\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2015-08-22 23:28+0200\n"
|
||||
"PO-Revision-Date: 2015-08-22 15:09+0100\n"
|
||||
"Last-Translator: Christian Berg <xeniac@posteo.at>\n"
|
||||
"PO-Revision-Date: 2015-09-06 00:13+0200\n"
|
||||
"Last-Translator: Christian Berg <xeniac.at@gmail.com>\n"
|
||||
"Language-Team: Kasu <verein@kasu.at>\n"
|
||||
"Language: de\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@@ -375,7 +375,7 @@ msgstr "%s wurde erfolgreich aktualisiert."
|
||||
#: views.py:96
|
||||
#, 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 anlagen."
|
||||
msgstr "%s wurde erfolgreich hinzugefügt. Du kannst eine neue eintragen."
|
||||
|
||||
#: views.py:113 views.py:129
|
||||
msgid "Event does not exist"
|
||||
|
||||
41
src/mahjong_ranking/management/commands/export-ranking.py
Normal file
41
src/mahjong_ranking/management/commands/export-ranking.py
Normal file
@@ -0,0 +1,41 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Export Mahjong Rankings...
|
||||
"""
|
||||
|
||||
from operator import itemgetter
|
||||
from django.core.management.base import BaseCommand
|
||||
from mahjong_ranking.models import SeasonRanking
|
||||
from openpyxl import Workbook
|
||||
|
||||
|
||||
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:
|
||||
print row
|
||||
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)
|
||||
@@ -85,7 +85,6 @@ class Command(BaseCommand):
|
||||
self.add_players(hanchan)
|
||||
hanchan.save()
|
||||
|
||||
|
||||
def handle(self, *args, **options):
|
||||
num_hanchans = int(options.get('hanchans', 4))
|
||||
self.user_list = list(auth.get_user_model().objects.all())
|
||||
@@ -93,5 +92,3 @@ class Command(BaseCommand):
|
||||
for event in Event.objects.all():
|
||||
for i in range(random.randrange(2, 8)):
|
||||
self.create_hanchan(event)
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
__author__ = 'christian'
|
||||
|
||||
from datetime import date
|
||||
|
||||
from django.db import models
|
||||
|
||||
|
||||
class HanchanManager(models.Manager):
|
||||
|
||||
use_for_related_fields = True
|
||||
|
||||
def confirmed_hanchans(self, user=None, **kwargs):
|
||||
@@ -77,3 +77,25 @@ class SeasonRankingManager(models.Manager):
|
||||
def season_list(self):
|
||||
values_list = self.model.objects.values_list('season', flat=True)
|
||||
return values_list.order_by('season').distinct()
|
||||
|
||||
def json_data(self, season=None):
|
||||
season = season or date.today().year
|
||||
json_data = {}
|
||||
values = self.filter(season=season, placement__isnull=False)
|
||||
values = values.values('placement', 'user_id', 'user__username',
|
||||
'user__first_name', 'user__last_name', 'avg_placement', 'avg_score',
|
||||
'hanchan_count', 'good_hanchans', 'won_hanchans')
|
||||
for user in values:
|
||||
json_data[user['user_id']] = {
|
||||
'placement': user['placement'],
|
||||
'user_id': user['user_id'],
|
||||
'username': user['user__username'],
|
||||
'first_name': user['user__first_name'],
|
||||
'last_name': user['user__last_name'],
|
||||
'avg_placement': user['avg_placement'],
|
||||
'avg_score': user['avg_score'],
|
||||
'hanchan_count': user['hanchan_count'],
|
||||
'good_hanchans': user['good_hanchans'],
|
||||
'won_hanchans': user['won_hanchans']
|
||||
}
|
||||
return json_data
|
||||
|
||||
@@ -36,38 +36,41 @@ class DenormalizationUpdateMiddleware(object):
|
||||
cache.set('ladder_ranking_queue', set(), 360)
|
||||
|
||||
for event_id in self.event_queue:
|
||||
self.update_event_placement()
|
||||
self.update_event_placements()
|
||||
for season in self.season_queue:
|
||||
self.update_season_placements()
|
||||
|
||||
|
||||
|
||||
return response
|
||||
|
||||
def recalculate_event_rankings(self, queue):
|
||||
# recalculate tournament (event) rankings:
|
||||
for event_id, user_id in queue:
|
||||
logger.info("recalculate %d tournament Ranking in %s", user_id, event_id)
|
||||
ranking = models.EventRanking.objects.get_or_create(event_id=event_id, user_id=user_id)[0]
|
||||
logger.info("recalculate %d tournament Ranking in %s",
|
||||
user_id, event_id)
|
||||
ranking = models.EventRanking.objects.get_or_create(
|
||||
event_id=event_id, user_id=user_id)[0]
|
||||
ranking.recalculate()
|
||||
self.event_queue.add(event_id)
|
||||
return queue
|
||||
|
||||
def recalulate_kyu_dan_ranking(self, queue):
|
||||
for user_id in queue:
|
||||
ranking = models.KyuDanRanking.objects.get_or_create(user_id=user_id)[0]
|
||||
ranking = models.KyuDanRanking.objects.get_or_create(user_id=user_id)[
|
||||
0]
|
||||
ranking.recalculate()
|
||||
return queue
|
||||
|
||||
def recalculate_ladder_ranking(self, queue):
|
||||
for season, user_id in queue:
|
||||
ladder = models.SeasonRanking.objects.get_or_create(user_id=user_id, season=season)[0]
|
||||
ladder = models.SeasonRanking.objects.get_or_create(
|
||||
user_id=user_id, season=season)[0]
|
||||
ladder.recalculate()
|
||||
self.season_queue.add(season)
|
||||
|
||||
def update_event_placements(self):
|
||||
for event_id in self.event_queue:
|
||||
eventranking_set = models.EventRanking.objects.filter(event_id=event_id).order_by('avg_placement', '-avg_score')
|
||||
eventranking_set = models.EventRanking.objects.filter(
|
||||
event_id=event_id).order_by('avg_placement', '-avg_score')
|
||||
placement = 1
|
||||
for ranking in eventranking_set:
|
||||
ranking.placement = placement
|
||||
|
||||
157
src/mahjong_ranking/migrations/0001_initial.py
Normal file
157
src/mahjong_ranking/migrations/0001_initial.py
Normal file
@@ -0,0 +1,157 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('events', '0005_auto_20150907_2021'),
|
||||
]
|
||||
|
||||
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)),
|
||||
('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)),
|
||||
('start', models.DateTimeField(
|
||||
help_text='Wichtig damit die richtigen Hanchans in die Wertung kommen.', verbose_name='Beginn')),
|
||||
('player1_input_score', models.IntegerField(verbose_name='Punkte')),
|
||||
('player1_game_score', models.PositiveIntegerField(
|
||||
default=0, verbose_name='Punkte', editable=False)),
|
||||
('player1_placement', models.PositiveSmallIntegerField(
|
||||
default=0, editable=False)),
|
||||
('player1_kyu_points', models.SmallIntegerField(
|
||||
null=True, editable=False, blank=True)),
|
||||
('player1_dan_points', models.SmallIntegerField(
|
||||
null=True, editable=False, blank=True)),
|
||||
('player1_bonus_points', models.SmallIntegerField(
|
||||
null=True, editable=False, blank=True)),
|
||||
('player1_comment', models.CharField(verbose_name='Anmerkung',
|
||||
max_length=255, editable=False, blank=True)),
|
||||
('player2_input_score', models.IntegerField(verbose_name='Punkte')),
|
||||
('player2_game_score', models.PositiveIntegerField(
|
||||
default=0, verbose_name='Punkte', editable=False)),
|
||||
('player2_placement', models.PositiveSmallIntegerField(
|
||||
default=0, editable=False)),
|
||||
('player2_kyu_points', models.SmallIntegerField(
|
||||
null=True, editable=False, blank=True)),
|
||||
('player2_dan_points', models.SmallIntegerField(
|
||||
null=True, editable=False, blank=True)),
|
||||
('player2_bonus_points', models.SmallIntegerField(
|
||||
null=True, editable=False, blank=True)),
|
||||
('player2_comment', models.CharField(verbose_name='Anmerkung',
|
||||
max_length=255, editable=False, blank=True)),
|
||||
('player3_input_score', models.IntegerField(verbose_name='Punkte')),
|
||||
('player3_game_score', models.PositiveIntegerField(
|
||||
default=0, verbose_name='Punkte', editable=False)),
|
||||
('player3_placement', models.PositiveSmallIntegerField(
|
||||
default=0, editable=False)),
|
||||
('player3_kyu_points', models.SmallIntegerField(
|
||||
null=True, editable=False, blank=True)),
|
||||
('player3_dan_points', models.SmallIntegerField(
|
||||
null=True, editable=False, blank=True)),
|
||||
('player3_bonus_points', models.SmallIntegerField(
|
||||
null=True, editable=False, blank=True)),
|
||||
('player3_comment', models.CharField(verbose_name='Anmerkung',
|
||||
max_length=255, editable=False, blank=True)),
|
||||
('player4_input_score', models.IntegerField(verbose_name='Punkte')),
|
||||
('player4_game_score', models.PositiveIntegerField(
|
||||
default=0, verbose_name='Punkte', editable=False)),
|
||||
('player4_placement', models.PositiveSmallIntegerField(
|
||||
default=0, editable=False)),
|
||||
('player4_kyu_points', models.SmallIntegerField(
|
||||
null=True, editable=False, blank=True)),
|
||||
('player4_dan_points', models.SmallIntegerField(
|
||||
null=True, editable=False, blank=True)),
|
||||
('player4_bonus_points', models.SmallIntegerField(
|
||||
null=True, editable=False, blank=True)),
|
||||
('player4_comment', models.CharField(verbose_name='Anmerkung',
|
||||
max_length=255, editable=False, blank=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=255, editable=False)),
|
||||
('season', models.PositiveSmallIntegerField(
|
||||
verbose_name='Saison', editable=False, db_index=True)),
|
||||
('event', models.ForeignKey(to='events.Event')),
|
||||
('player1', models.ForeignKey(related_name='user_hanchan+',
|
||||
verbose_name='Spieler 1', to=settings.AUTH_USER_MODEL)),
|
||||
('player2', models.ForeignKey(related_name='user_hanchan+',
|
||||
verbose_name='Spieler 2', to=settings.AUTH_USER_MODEL)),
|
||||
('player3', models.ForeignKey(related_name='user_hanchan+',
|
||||
verbose_name='Spieler 3', to=settings.AUTH_USER_MODEL)),
|
||||
('player4', models.ForeignKey(related_name='user_hanchan+',
|
||||
verbose_name='Spieler 4', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
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)),
|
||||
('legacy_date', models.DateField(null=True, blank=True)),
|
||||
('legacy_dan_points', models.PositiveIntegerField(default=0)),
|
||||
('legacy_kyu_points', models.PositiveIntegerField(default=0)),
|
||||
('user', models.OneToOneField(to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'ordering': ('-dan', '-dan_points', '-kyu_points'),
|
||||
'verbose_name': 'Ky\u016b/Dan Wertung',
|
||||
'verbose_name_plural': 'Ky\u016b/Dan Wertungen',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SeasonRanking',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID',
|
||||
serialize=False, auto_created=True, primary_key=True)),
|
||||
('season', models.PositiveSmallIntegerField(verbose_name='Saison')),
|
||||
('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)),
|
||||
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'ordering': ('placement', 'avg_placement', '-avg_score'),
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mahjong_ranking', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='kyudanranking',
|
||||
name='legacy_hanchan_count',
|
||||
field=models.PositiveIntegerField(default=0),
|
||||
),
|
||||
]
|
||||
0
src/mahjong_ranking/migrations/__init__.py
Normal file
0
src/mahjong_ranking/migrations/__init__.py
Normal file
@@ -1,7 +1,9 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
# TODO: Rankings archiv Flag erstellen, womit sie nicht mehr neuberechnet werden dürfen.
|
||||
# TODO: Rankings archiv Flag erstellen, womit sie nicht mehr neuberechnet
|
||||
# werden dürfen.
|
||||
|
||||
from __future__ import division
|
||||
from datetime import date
|
||||
|
||||
from django.conf import settings
|
||||
@@ -9,11 +11,10 @@ from django.core.exceptions import ValidationError
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from events.models import Event
|
||||
from . import KYU_RANKS, DAN_RANKS, DAN_RANKS_DICT, logger, set_dirty, MIN_HANCHANS_FOR_LADDER
|
||||
from . import KYU_RANKS, DAN_RANKS, DAN_RANKS_DICT, logger, set_dirty
|
||||
from . import managers
|
||||
|
||||
kyu_dan_rankings = set()
|
||||
@@ -40,7 +41,7 @@ class EventRanking(models.Model):
|
||||
ordering = ('placement', 'avg_placement', '-avg_score',)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('event-ranking', args=[self.tourney_id])
|
||||
return reverse('event-ranking', args=[self.event_id])
|
||||
|
||||
def recalculate(self):
|
||||
"""
|
||||
@@ -50,23 +51,33 @@ class EventRanking(models.Model):
|
||||
können zwar sehr leicht errechnet werden, es macht trotzdem Sinn
|
||||
sie zwischen zu speichern.
|
||||
"""
|
||||
logger.info(u'Recalculate EventRanking for Player %s in %s', self.user,
|
||||
self.event.name) # @IgnorePep8
|
||||
event_hanchans = Player.objects.confirmed_hanchans(user=self.user_id,
|
||||
event=self.event_id) # @IgnorePep8
|
||||
aggregator = event_hanchans.aggregate(
|
||||
models.Avg('placement'),
|
||||
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()
|
||||
logger.info(
|
||||
u'Recalculate EventRanking for Player %s in %s',
|
||||
self.user, self.event.name
|
||||
)
|
||||
sum_placement = 0.0
|
||||
sum_score = 0.0
|
||||
event_hanchans = Hanchan.objects.confirmed_hanchans(
|
||||
user=self.user_id,
|
||||
event=self.event_id
|
||||
)
|
||||
self.hanchan_count = event_hanchans.count()
|
||||
self.won_hanchans = 0
|
||||
self.good_hanchans = 0
|
||||
|
||||
if self.hanchan_count <= 0:
|
||||
self.delete()
|
||||
else:
|
||||
self.save()
|
||||
for hanchan in event_hanchans:
|
||||
hanchan.get_playerdata(user=self.user)
|
||||
sum_placement += hanchan.placement
|
||||
sum_score += hanchan.game_score
|
||||
self.won_hanchans += 1 if hanchan.placement == 1 else 0
|
||||
self.good_hanchans += 1 if hanchan.placement == 2 else 0
|
||||
self.avg_placement = sum_placement / self.hanchan_count
|
||||
self.avg_score = sum_score / self.hanchan_count
|
||||
self.save(force_update=True)
|
||||
|
||||
|
||||
|
||||
class Hanchan(models.Model):
|
||||
@@ -76,52 +87,88 @@ class Hanchan(models.Model):
|
||||
Außerdem gehört jede Hanchan zu einer Veranstaltung.
|
||||
"""
|
||||
event = models.ForeignKey(Event)
|
||||
start = models.DateTimeField(_('Start'),
|
||||
help_text=_('This is crucial to get the right Hanchans that scores')
|
||||
)
|
||||
start = models.DateTimeField(
|
||||
_('Start'),
|
||||
help_text=_('This is crucial to get the right Hanchans that scores')
|
||||
)
|
||||
|
||||
player1 = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='user_hanchan+', verbose_name=_('Player 1'))
|
||||
player1 = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL, related_name='user_hanchan+',
|
||||
verbose_name=_('Player 1'))
|
||||
player1_input_score = models.IntegerField(_('Score'))
|
||||
player1_game_score = models.PositiveIntegerField(_('Score'), default=0, editable=False)
|
||||
player1_placement = models.PositiveSmallIntegerField(default=0, editable=False)
|
||||
player1_kyu_points = models.SmallIntegerField(blank=True, null=True, editable=False)
|
||||
player1_dan_points = models.SmallIntegerField(blank=True, null=True, editable=False)
|
||||
player1_bonus_points = models.SmallIntegerField(blank=True, null=True, editable=False)
|
||||
player1_comment = models.CharField(_('Comment'), blank=True, max_length=255, editable=False)
|
||||
player1_game_score = models.PositiveIntegerField(
|
||||
_('Score'), default=0, editable=False)
|
||||
player1_placement = models.PositiveSmallIntegerField(
|
||||
default=0, editable=False)
|
||||
player1_kyu_points = models.SmallIntegerField(
|
||||
blank=True, null=True, editable=False)
|
||||
player1_dan_points = models.SmallIntegerField(
|
||||
blank=True, null=True, editable=False)
|
||||
player1_bonus_points = models.SmallIntegerField(
|
||||
blank=True, null=True, editable=False)
|
||||
player1_comment = models.CharField(
|
||||
_('Comment'), blank=True, max_length=255, editable=False)
|
||||
|
||||
player2 = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='user_hanchan+', verbose_name=_('Player 2'))
|
||||
player2 = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL, related_name='user_hanchan+',
|
||||
verbose_name=_('Player 2'))
|
||||
player2_input_score = models.IntegerField(_('Score'))
|
||||
player2_game_score = models.PositiveIntegerField(_('Score'), default=0, editable=False)
|
||||
player2_placement = models.PositiveSmallIntegerField(default=0, editable=False)
|
||||
player2_kyu_points = models.SmallIntegerField(blank=True, null=True, editable=False)
|
||||
player2_dan_points = models.SmallIntegerField(blank=True, null=True, editable=False)
|
||||
player2_bonus_points = models.SmallIntegerField(blank=True, null=True, editable=False)
|
||||
player2_comment = models.CharField(_('Comment'), blank=True, max_length=255, editable=False)
|
||||
player2_game_score = models.PositiveIntegerField(
|
||||
_('Score'), default=0, editable=False)
|
||||
player2_placement = models.PositiveSmallIntegerField(
|
||||
default=0, editable=False)
|
||||
player2_kyu_points = models.SmallIntegerField(
|
||||
blank=True, null=True, editable=False)
|
||||
player2_dan_points = models.SmallIntegerField(
|
||||
blank=True, null=True, editable=False)
|
||||
player2_bonus_points = models.SmallIntegerField(
|
||||
blank=True, null=True, editable=False)
|
||||
player2_comment = models.CharField(
|
||||
_('Comment'), blank=True, max_length=255, editable=False)
|
||||
|
||||
player3 = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='user_hanchan+', verbose_name=_('Player 3'))
|
||||
player3 = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL, related_name='user_hanchan+',
|
||||
verbose_name=_('Player 3'))
|
||||
player3_input_score = models.IntegerField(_('Score'))
|
||||
player3_game_score = models.PositiveIntegerField(_('Score'), default=0, editable=False)
|
||||
player3_placement = models.PositiveSmallIntegerField(default=0, editable=False)
|
||||
player3_kyu_points = models.SmallIntegerField(blank=True, null=True, editable=False)
|
||||
player3_dan_points = models.SmallIntegerField(blank=True, null=True, editable=False)
|
||||
player3_bonus_points = models.SmallIntegerField(blank=True, null=True, editable=False)
|
||||
player3_comment = models.CharField(_('Comment'), blank=True, max_length=255, editable=False)
|
||||
player3_game_score = models.PositiveIntegerField(
|
||||
_('Score'), default=0, editable=False)
|
||||
player3_placement = models.PositiveSmallIntegerField(
|
||||
default=0, editable=False)
|
||||
player3_kyu_points = models.SmallIntegerField(
|
||||
blank=True, null=True, editable=False)
|
||||
player3_dan_points = models.SmallIntegerField(
|
||||
blank=True, null=True, editable=False)
|
||||
player3_bonus_points = models.SmallIntegerField(
|
||||
blank=True, null=True, editable=False)
|
||||
player3_comment = models.CharField(
|
||||
_('Comment'), blank=True, max_length=255, editable=False)
|
||||
|
||||
player4 = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='user_hanchan+', verbose_name=_('Player 4'))
|
||||
player4 = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL, related_name='user_hanchan+',
|
||||
verbose_name=_('Player 4'))
|
||||
player4_input_score = models.IntegerField(_('Score'))
|
||||
player4_game_score = models.PositiveIntegerField(_('Score'), default=0, editable=False)
|
||||
player4_placement = models.PositiveSmallIntegerField(default=0, editable=False)
|
||||
player4_kyu_points = models.SmallIntegerField(blank=True, null=True, editable=False)
|
||||
player4_dan_points = models.SmallIntegerField(blank=True, null=True, editable=False)
|
||||
player4_bonus_points = models.SmallIntegerField(blank=True, null=True, editable=False)
|
||||
player4_comment = models.CharField(_('Comment'), blank=True, max_length=255, editable=False)
|
||||
player4_game_score = models.PositiveIntegerField(
|
||||
_('Score'), default=0, editable=False)
|
||||
player4_placement = models.PositiveSmallIntegerField(
|
||||
default=0, editable=False)
|
||||
player4_kyu_points = models.SmallIntegerField(
|
||||
blank=True, null=True, editable=False)
|
||||
player4_dan_points = models.SmallIntegerField(
|
||||
blank=True, null=True, editable=False)
|
||||
player4_bonus_points = models.SmallIntegerField(
|
||||
blank=True, null=True, editable=False)
|
||||
player4_comment = models.CharField(
|
||||
_('Comment'), blank=True, max_length=255, editable=False)
|
||||
|
||||
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.')
|
||||
help_text=_(
|
||||
'Only valid and confirmed Hanchans '
|
||||
'will be counted in the rating.')
|
||||
)
|
||||
player_names = models.CharField(max_length=255, editable=False)
|
||||
season = models.PositiveSmallIntegerField(_('Season'), editable=False, db_index=True)
|
||||
season = models.PositiveSmallIntegerField(
|
||||
_('Season'), editable=False, db_index=True)
|
||||
objects = managers.HanchanManager()
|
||||
|
||||
class Meta(object):
|
||||
@@ -137,7 +184,8 @@ class Hanchan(models.Model):
|
||||
def clean(self):
|
||||
"""
|
||||
Check if 4 different Players are attending the Game,
|
||||
if the Game between the opening hours and the Hanchan has a total of 100.000 Points.
|
||||
if the Game between the opening hours and the Hanchan has a total of
|
||||
100.000 Points.
|
||||
"""
|
||||
errors = {}
|
||||
score_sum = 0
|
||||
@@ -155,18 +203,21 @@ class Hanchan(models.Model):
|
||||
score_sum += input_score
|
||||
game_score = input_score if input_score > 0 else 0
|
||||
if player in player_set:
|
||||
errors['player%d' % i] = _("%s can't attend the same game multiple times") % player
|
||||
errors['player%d' % i] = _(
|
||||
"%s can't attend the same game multiple times") % player
|
||||
else:
|
||||
player_set.add(player)
|
||||
setattr(self, 'player%d_game_score' % i, game_score)
|
||||
|
||||
# Check if the game was played during the event
|
||||
if self.start > timezone.now():
|
||||
errors['start'] = _("Games in the future may not be added, Dr. Brown")
|
||||
errors['start'] = _(
|
||||
"Games in the future may not be added, Dr. Brown")
|
||||
elif not (self.event.start <= self.start <= self.event.end):
|
||||
errors['start'] = _("Only games during the event are allowed")
|
||||
elif score_sum < 100000:
|
||||
errors['player4_input_score'] = _('Gamescore is lower then 100.000 Pt.')
|
||||
errors['player4_input_score'] = _(
|
||||
'Gamescore is lower then 100.000 Pt.')
|
||||
elif score_sum > 100000:
|
||||
errors['player4_input_score'] = _('Gamescore is over 100.000 Pt.')
|
||||
|
||||
@@ -190,12 +241,18 @@ class Hanchan(models.Model):
|
||||
else:
|
||||
player['placement'] = placement
|
||||
setattr(self, "player%d" % player_nr, player['user'])
|
||||
setattr(self, "player%d_input_score" % player_nr, player['input_score'])
|
||||
setattr(self, "player%d_game_score" % player_nr, player['game_score'])
|
||||
setattr(self, "player%d_placement" % player_nr, player['placement'])
|
||||
setattr(self, "player%d_kyu_points" % player_nr, player['kyu_points'])
|
||||
setattr(self, "player%d_dan_points" % player_nr, player['dan_points'])
|
||||
setattr(self, "player%d_bonus_points" % player_nr, player['bonus_points'])
|
||||
setattr(self, "player%d_input_score" %
|
||||
player_nr, player['input_score'])
|
||||
setattr(self, "player%d_game_score" %
|
||||
player_nr, player['game_score'])
|
||||
setattr(self, "player%d_placement" %
|
||||
player_nr, player['placement'])
|
||||
setattr(self, "player%d_kyu_points" %
|
||||
player_nr, player['kyu_points'])
|
||||
setattr(self, "player%d_dan_points" %
|
||||
player_nr, player['dan_points'])
|
||||
setattr(self, "player%d_bonus_points" %
|
||||
player_nr, player['bonus_points'])
|
||||
setattr(self, "player%d_comment" % player_nr, player['comment'])
|
||||
other_player_placement = player['placement']
|
||||
other_player_game_score = player['game_score']
|
||||
@@ -206,13 +263,13 @@ class Hanchan(models.Model):
|
||||
|
||||
def get_absolute_url(self):
|
||||
return "{url:s}#{id:d}".format(
|
||||
url=reverse('event-hanchan-list', kwargs={'event':self.event_id}),
|
||||
id= self.pk
|
||||
url=reverse('event-hanchan-list', kwargs={'event': self.event_id}),
|
||||
id=self.pk
|
||||
)
|
||||
|
||||
def get_playerdata(self, user):
|
||||
"""i small workaround to access score, placement and points of a
|
||||
specific user prominent from a in the user templates"""
|
||||
"""small workaround to access score, placement and points of a
|
||||
specific user prominent in the user templates"""
|
||||
for player in ('player1', 'player2', 'player3', 'player4'):
|
||||
if getattr(self, player) == user:
|
||||
self.user = user
|
||||
@@ -252,7 +309,8 @@ class Hanchan(models.Model):
|
||||
'comment': getattr(self, 'player%d_comment' % i),
|
||||
})
|
||||
# sort player by Score:
|
||||
return sorted(player_list, key=lambda player: player['input_score'], reverse=True)
|
||||
return sorted(player_list, key=lambda player: player['input_score'],
|
||||
reverse=True)
|
||||
|
||||
def save(self, **kwargs):
|
||||
self.season = self.event.mahjong_season or date.today().year
|
||||
@@ -276,12 +334,13 @@ class KyuDanRanking(models.Model):
|
||||
good_hanchans = models.PositiveIntegerField(default=0)
|
||||
hanchan_count = models.PositiveIntegerField(default=0)
|
||||
legacy_date = models.DateField(blank=True, null=True)
|
||||
legacy_hanchan_count = models.PositiveIntegerField(default=0)
|
||||
legacy_dan_points = models.PositiveIntegerField(default=0)
|
||||
legacy_kyu_points = models.PositiveIntegerField(default=0)
|
||||
wins_in_a_row = 0
|
||||
|
||||
class Meta(object):
|
||||
ordering = ('-dan_points', '-kyu_points',)
|
||||
ordering = ('-dan', '-dan_points', '-kyu_points',)
|
||||
verbose_name = _(u'Kyū/Dan Ranking')
|
||||
verbose_name_plural = _(u'Kyū/Dan Rankings')
|
||||
|
||||
@@ -316,15 +375,18 @@ class KyuDanRanking(models.Model):
|
||||
|
||||
hanchan.dan_points += bonus_points
|
||||
hanchan.bonus_points += bonus_points
|
||||
hanchan.player_comment += '3 Siege in Folge: +%d Punkte auf den %d. Dan. ' % (bonus_points, new_dan_rank)
|
||||
hanchan.player_comment += '3 Siege in Folge: +%d Punkte auf den ' \
|
||||
'%d. Dan. ' % (
|
||||
bonus_points, new_dan_rank)
|
||||
self.dan_points += bonus_points
|
||||
self.wins_in_a_row = 0
|
||||
|
||||
# TODO: Komplett Überabreiten!
|
||||
def append_tournament_bonuspoints(self, hanchan):
|
||||
"""
|
||||
Prüft ob es die letzte Hanchan in einem Turnier war. Wenn ja werden
|
||||
bei Bedarf Bonuspunkte vergeben, falls der Spieler das Turnier gewonnen
|
||||
hat.
|
||||
bei Bedarf Bonuspunkte vergeben, falls der Spieler das Turnier
|
||||
gewonnen hat.
|
||||
:param hanchan: Ein Player Objekt
|
||||
"""
|
||||
bonus_points = 0
|
||||
@@ -333,24 +395,27 @@ class KyuDanRanking(models.Model):
|
||||
).order_by('-start')
|
||||
last_hanchan_this_event = hanchans_this_event[0]
|
||||
if hanchan != last_hanchan_this_event:
|
||||
return # Das braucht nur am Ende eines Turnieres gemacht werden.
|
||||
event_ranking = EventRanking.objects.get(
|
||||
user=self.user,
|
||||
event=hanchan.event)
|
||||
if event_ranking.placement == 1:
|
||||
bonus_points += 4
|
||||
hanchan.comment += '+4 Punkte für den Sieg des Turnieres. '
|
||||
if event_ranking.avg_placement == 1:
|
||||
bonus_points += 8
|
||||
hanchan.comment += '+8 Pkt: alle Spiele des Turnieres gewonnen. '
|
||||
return False # Das braucht nur am Ende eines Turnieres gemacht werden.
|
||||
else:
|
||||
event_ranking = EventRanking.objects.get(
|
||||
user=self.user,
|
||||
event=hanchan.event
|
||||
)
|
||||
if event_ranking.placement == 1:
|
||||
bonus_points += 4
|
||||
hanchan.player_comment += u'+4 Punkte Turnier gewonnen. '
|
||||
if event_ranking.avg_placement == 1:
|
||||
bonus_points += 8
|
||||
hanchan.player_comment += u'+8 Pkt: alle Spiele des Turnieres gewonnen. '
|
||||
|
||||
if bonus_points and self.dan:
|
||||
hanchan.dan_points += bonus_points
|
||||
self.dan_points += bonus_points
|
||||
elif bonus_points:
|
||||
hanchan.kyu_points += bonus_points
|
||||
self.kyu_points += bonus_points
|
||||
hanchan.bonus_points += bonus_points
|
||||
if bonus_points and self.dan:
|
||||
hanchan.dan_points += bonus_points
|
||||
self.dan_points += bonus_points
|
||||
elif bonus_points:
|
||||
hanchan.kyu_points += bonus_points
|
||||
self.kyu_points += bonus_points
|
||||
hanchan.bonus_points += bonus_points
|
||||
return True
|
||||
|
||||
def get_absolute_url(self):
|
||||
if self.dan or self.dan_points > 0:
|
||||
@@ -363,32 +428,33 @@ class KyuDanRanking(models.Model):
|
||||
Fetches all valid Hanchans from this Player and recalculates his
|
||||
Kyu/Dan Ranking.
|
||||
"""
|
||||
self.kyu_points = self.legacy_kyu_points or 0
|
||||
self.dan_points = self.legacy_dan_points or 0
|
||||
self.dan = None
|
||||
self.dan_points = self.legacy_dan_points or 0
|
||||
self.kyu = None
|
||||
self.won_hanchans = 0
|
||||
self.good_hanchans = 0
|
||||
self.kyu_points = self.legacy_kyu_points or 0
|
||||
self.hanchan_count = self.legacy_hanchan_count or 0
|
||||
|
||||
logger.info("recalculating Kyu/Dan punkte for %s...", self.user)
|
||||
self.good_hanchans = 0
|
||||
self.won_hanchans = 0
|
||||
|
||||
logger.info("recalculating Kyu/Dan points for %s...", self.user)
|
||||
self.update_rank()
|
||||
valid_hanchans = Hanchan.objects.confirmed_hanchans(user=self.user)
|
||||
valid_hanchans = valid_hanchans.order_by('start')
|
||||
if self.legacy_date:
|
||||
valid_hanchans = valid_hanchans.filter(start__gt=self.legacy_date)
|
||||
|
||||
self.hanchan_count = valid_hanchans.count()
|
||||
self.hanchan_count += valid_hanchans.count()
|
||||
for hanchan in valid_hanchans:
|
||||
hanchan.get_playerdata(self.user)
|
||||
hanchan.bonus_points=0
|
||||
hanchan.player_comment=""
|
||||
hanchan.bonus_points = 0
|
||||
hanchan.player_comment = u""
|
||||
self.update_hanchan_points(hanchan)
|
||||
if hanchan.event.mahjong_tournament:
|
||||
self.append_tournament_bonuspoints(hanchan)
|
||||
self.update_rank()
|
||||
self.append_3_in_a_row_bonuspoints(hanchan)
|
||||
self.update_rank()
|
||||
self.won_hanchans += 1 if hanchan.placement == 1 else 0
|
||||
self.won_hanchans += 1 if hanchan.placement == 1 else 0
|
||||
self.good_hanchans += 1 if hanchan.placement == 2 else 0
|
||||
hanchan.update_playerdata(self.user)
|
||||
hanchan.save(force_update=True)
|
||||
@@ -447,7 +513,8 @@ class KyuDanRanking(models.Model):
|
||||
hanchan.kyu_points -= (self.kyu_points + hanchan.kyu_points)
|
||||
self.kyu_points += hanchan.kyu_points
|
||||
|
||||
# TODO: Merkwürdige Methode die zwar funktioniert aber nicht sehr aussagekräfig ist. Überarbeiten?
|
||||
# TODO: Merkwürdige Methode die zwar funktioniert aber nicht sehr
|
||||
# aussagekräfig ist. Überarbeiten?
|
||||
def update_rank(self):
|
||||
if self.dan and self.dan_points < 0:
|
||||
self.dan_points = 0
|
||||
@@ -493,7 +560,8 @@ class SeasonRanking(models.Model):
|
||||
return reverse('player-ladder-score', args=[self.user.username])
|
||||
|
||||
def recalculate(self):
|
||||
season_hanchans = Hanchan.objects.season_hanchans(user=self.user, season=self.season)
|
||||
season_hanchans = Hanchan.objects.season_hanchans(
|
||||
user=self.user, season=self.season)
|
||||
sum_placement = 0
|
||||
sum_score = 0
|
||||
self.placement = None
|
||||
@@ -501,7 +569,9 @@ class SeasonRanking(models.Model):
|
||||
self.good_hanchans = 0
|
||||
self.won_hanchans = 0
|
||||
|
||||
logger.info(u'Recalculate LadderRanking for Player %s in Season %s', self.user, self.season)
|
||||
logger.info(
|
||||
u'Recalculate LadderRanking for Player %s in Season %s',
|
||||
self.user, self.season)
|
||||
for hanchan in season_hanchans:
|
||||
sum_placement += hanchan.placement
|
||||
sum_score += hanchan.game_score
|
||||
@@ -517,16 +587,21 @@ class SeasonRanking(models.Model):
|
||||
|
||||
|
||||
def update_ranking(sender, instance, **kwargs):
|
||||
for user in (instance.player1, instance.player2, instance.player3, instance.player4):
|
||||
logger.debug("Marking %s's kyu/dan for recalculation", user)
|
||||
for user in (
|
||||
instance.player1, instance.player2, instance.player3, instance.player4):
|
||||
logger.debug("marking %s's kyu/dan for recalculation", user)
|
||||
set_dirty(user=user.id)
|
||||
logger.debug(
|
||||
"marking event %s for recalculation.", instance.event)
|
||||
set_dirty(event=instance.event_id, user=user.id)
|
||||
|
||||
if instance.season:
|
||||
logger.debug("Marking %s's ladder %i season for recalculation.", user, instance.season)
|
||||
logger.debug(
|
||||
"marking %s's ladder %i season for recalculation.", user,
|
||||
instance.season)
|
||||
set_dirty(user=user.id, season=instance.season)
|
||||
if instance.event.mahjong_tournament:
|
||||
logger.debug("Marking tournament %s for recalculation.", instance.event)
|
||||
set_dirty(event=instance.event_id, user=user.id)
|
||||
set_dirty(season=instance.season)
|
||||
|
||||
|
||||
models.signals.pre_delete.connect(update_ranking, sender=Hanchan)
|
||||
models.signals.post_save.connect(update_ranking, sender=Hanchan)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{% extends "events/event_detail.html" %}
|
||||
{% load i18n humanize %}
|
||||
{% load i18n humanize thumbnail %}
|
||||
|
||||
{% block title %}Hanchans: {{ event.name }}{% endblock %}
|
||||
|
||||
@@ -7,38 +7,45 @@
|
||||
<h2 class="grid_12">{% trans 'Played Hanchans' %}</h2>
|
||||
<p> </p>
|
||||
{% for hanchan in hanchan_list %}
|
||||
<h3 class="grid_12" id="{{ hanchan.pk }}">{{hanchan.start|time:'H:i'}}: {{ hanchan.player_names }}</h3>
|
||||
{% for player in hanchan.player_list %}
|
||||
<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">
|
||||
<p><a class="player" href="{% url 'player-ladder-score' player.user %}" title="{{ player.comment }}">{{ player.user }}</a></p>
|
||||
<p><strong>{{ player.placement|ordinal }} {% trans 'Place' %}</strong><br />
|
||||
<strong>{% trans 'Score' %}:</strong> {{ player.game_score|intcomma }}<br />
|
||||
{% if player.dan_points != None %}
|
||||
<strong>{% trans 'Dan Points' %}:</strong> {{ player.dan_points }}
|
||||
{% else %}
|
||||
<strong>{% trans 'Kyu Points' %}:</strong> {{ player.kyu_points|default:0 }}
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if not hanchan.confirmed %}
|
||||
<p class="grid_12 error">Diese Hanchan wurde nicht anerkannt und wird daher nicht gezählt.</p>
|
||||
{% elif hanchan.comment %}
|
||||
<p class="grid_12">{{ hanchan.comment }}</p>
|
||||
{% endif %}
|
||||
<p class="grid_12 more_link">
|
||||
{% if perms.mahjong_ranking.delete_hanchan %}
|
||||
<a href="{% url 'delete-hanchan' hanchan.pk %}" class="button"><span class="fa fa-trash"></span> {% trans 'Delete Hanchan' %}</a>
|
||||
<h3 class="grid_12" id="{{ hanchan.pk }}">{{hanchan.start|time:'H:i'}}: {{ hanchan.player_names }}</h3>
|
||||
{% for player in hanchan.player_list %}
|
||||
<div class="grid_3">
|
||||
<a href="{% url 'player-ladder-score' player.user %}" class="avatar"><img
|
||||
src="{% thumbnail player.user.avatar|default:'unknown_profile.jpg' 'avatar' %}"
|
||||
width="70" height="70" alt="" title="{{ player.user }}"/></a>
|
||||
<a class="player" href="{% url 'player-ladder-score' player.user %}" title="{{ player.comment }}">{{ player.user }}</a>
|
||||
<ul class="fa-ul">
|
||||
<li><strong>{{ player.placement|ordinal }} {% trans 'Place' %}</strong></li>
|
||||
<li><strong>{% trans 'Score' %}:</strong> {{ player.game_score|intcomma }}</li>
|
||||
{% if player.dan_points != None %}
|
||||
<li><strong>{% trans 'Dan Points' %}:</strong> {{ player.dan_points }}</li>
|
||||
{% else %}
|
||||
<li><strong>{% trans 'Kyu Points' %}:</strong> {{ player.kyu_points|default:0 }}</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if not hanchan.confirmed %}
|
||||
<p class="grid_12 error">Diese Hanchan wurde nicht anerkannt und wird daher nicht gezählt.</p>
|
||||
{% elif hanchan.comment %}
|
||||
<p class="grid_12">{{ hanchan.comment }}</p>
|
||||
{% endif %}
|
||||
{% if perms.mahjong_ranking.change_hanchan %}
|
||||
<a href="{% url 'edit-hanchan' hanchan.pk %}" class="button"><span class="fa fa-pencil"></span> {% trans 'Edit Hanchan' %}</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
<p class="grid_12 more_link">
|
||||
{% if perms.mahjong_ranking.delete_hanchan %}
|
||||
<a href="{% url 'delete-hanchan' hanchan.pk %}" class="button">
|
||||
<span class="fa fa-trash"></span>
|
||||
{% trans 'Delete Hanchan' %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if perms.mahjong_ranking.change_hanchan %}
|
||||
<a href="{% url 'edit-hanchan' hanchan.pk %}" class="button">
|
||||
<span class="fa fa-pencil"></span>
|
||||
{% trans 'Edit Hanchan' %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
{% empty %}
|
||||
<h3 class="grid_12">{% trans 'No Hanchan has been added to this event yet.'%}</h3>
|
||||
<h3 class="grid_12">{% trans 'No Hanchan has been added to this event yet.'%}</h3>
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{% extends "events/event_detail.html" %}
|
||||
|
||||
{% load i18n comments%}
|
||||
{% load i18n comments humanize thumbnail %}
|
||||
|
||||
{% block title %}{% trans "Tournament Ranking" %}: {{ event.name }}{% endblock %}
|
||||
{% block teaser %}<h1>{% trans "Tournament Ranking" %}: {{ event.name }}</h1>{% endblock %}
|
||||
@@ -28,17 +27,14 @@
|
||||
{% for player in eventranking_list %}
|
||||
<tr>
|
||||
<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><a href="{{ player.get_absolute_url }}?season={{season}}"><img
|
||||
src="{% thumbnail player.user.avatar|default:'unknown_profile.jpg' 'avatar' %}"
|
||||
width="70" height="70" class="avatar" alt=""/></a></td>
|
||||
<td><a href="{{ player.get_absolute_url }}?season={{season}}">{{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|intcomma }}</td>
|
||||
<td class="right">{{player.hanchan_count}}</td>
|
||||
<td class="right">{{player.good_hanchans}}</td>
|
||||
<td class="right">{{player.won_hanchans}}</td>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{% extends "events/event_detail.html" %}
|
||||
{% load i18n humanize %}
|
||||
{% load i18n humanize thumbnail %}
|
||||
|
||||
{% block meta_title %}{% trans 'Delete Hanchan' %}{% endblock %}
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
<h3 class="grid_12" id="{{ hanchan.pk }}">{{hanchan.start|time:'H:i'}}: {{ hanchan.player_names }}</h3>
|
||||
{% for player in hanchan.player_list %}
|
||||
<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 %}"
|
||||
src="{% thumbnail user.avatar|default:'unknown_profile.jpg' 'avatar' %}"
|
||||
width="70" height="70"
|
||||
class="avatar" alt="{{ player.user }}" title="{{ player.user }}"/></a>
|
||||
<div class="grid_2">
|
||||
<p><a class="player" href="{% url 'player-ladder-score' player.user %}" title="{{ player.comment }}">{{ player.user }}</a></p>
|
||||
|
||||
@@ -40,25 +40,42 @@ $('input[name$="_input_score"]').change(function() {recalculate_values(this);});
|
||||
<table>
|
||||
<thead><tr>
|
||||
<th width="25%">{% trans 'Player' %}</th>
|
||||
<th width="75%">{% trans 'Score' %}</th>
|
||||
<th width="25%">{% trans 'Score' %}</th>
|
||||
<th width="50%">{% trans 'Comment' %}</th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
{% with event_formset as form %}{% include "form.html" %} {% endwith %}
|
||||
<tr>
|
||||
<td>{{ form.player1 }} {% if form.player1.errors %}{{ form.player1.errors }}{% endif %}</td>
|
||||
<td>{{ form.player1_input_score}} {% if form.player1_input_score.errors %}{{ form.player1_input_score.errors }}{% endif %}</td>
|
||||
<td>{{ form.player1_input_score}}</td>
|
||||
<td>
|
||||
{{ form.instance.player1_comment}}
|
||||
{% if form.player1_input_score.errors %}{{ form.player1_input_score.errors }}{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ form.player2 }} {% if form.player2.errors %}{{ form.player2.errors }}{% endif %}</td>
|
||||
<td>{{ form.player2_input_score}} {% if form.player2_input_score.errors %}{{ form.player2_input_score.errors }}{% endif %}</td>
|
||||
<td>{{ form.player2_input_score}}</td>
|
||||
<td>
|
||||
{{ form.instance.player2_comment }}
|
||||
{% if form.player2_input_score.errors %}{{ form.player2_input_score.errors }}{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ form.player3 }} {% if form.player3.errors %}{{ form.player3.errors }}{% endif %}</td>
|
||||
<td>{{ form.player3_input_score}} {% if form.player3_input_score.errors %}{{ form.player3_input_score.errors }}{% endif %}</td>
|
||||
<td>{{ form.player3_input_score}}</td>
|
||||
<td>
|
||||
{{ form.instance.player3_comment }}
|
||||
{% if form.player3_input_score.errors %}{{ form.player3_input_score.errors }}{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ form.player4 }} {% if form.player4.errors %}{{ form.player4.errors }}{% endif %}</td>
|
||||
<td>{{ form.player4_input_score}} {% if form.player4_input_score.errors %}{{ form.player4_input_score.errors }}{% endif %}</td>
|
||||
<td>{{ form.player4_input_score}}</td>
|
||||
<td>
|
||||
{{ form.instance.player4_comment }}
|
||||
{% if form.player4_input_score.errors %}{{ form.player4_input_score.errors }}{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot><tr>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
{% extends "mahjong_ranking/page.html" %}
|
||||
{% load i18n %}
|
||||
{% load i18n thumbnail %}
|
||||
|
||||
{% block title %}{% trans 'Player List' %}{% endblock %}
|
||||
{% block teaser %}<h1>{% trans 'Player List' %}</h1>{% endblock %}
|
||||
|
||||
{% block redbox %}{% include 'mahjong_ranking/ladder_redbox.html' %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<table>
|
||||
<thead>
|
||||
@@ -40,11 +42,9 @@
|
||||
{% for ranking in kyudanranking_list %}
|
||||
<tr>
|
||||
<td>
|
||||
{% 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 %}
|
||||
<a href="{{ ranking.get_absolute_url }}"><img
|
||||
src="{% thumbnail ranking.user.avatar|default:'unknown_profile.jpg' 'avatar' %}"
|
||||
width="70" height="70" alt="" /></a>
|
||||
</td>
|
||||
<td><a href="{{ ranking.get_absolute_url }}">{{ ranking.user }}</a></td>
|
||||
<td>{% if user.is_authenticated %}{{ranking.user.last_name}} {{ranking.user.first_name}}{% else %}---{% endif %}</td>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
{% load i18n %}
|
||||
|
||||
<h2>{% trans 'Latest Hanchans' %}</h2>
|
||||
<ul class="fa-ul">
|
||||
{% for hanchan in latest_hanchan_list %}
|
||||
<li><span class="fa-li fa fa-table"></span>
|
||||
<a href="{% url 'event-hanchan-list' hanchan.event_id %}">
|
||||
<time datetime="{{ hanchan.start|date:'c' }}">{{ hanchan.start|date:'D' }}
|
||||
{{ hanchan.start|date:'SHORT_DATE_FORMAT' }} {{hanchan.start|time:'H:i'}}
|
||||
</time></a>:<br />
|
||||
<small>{{hanchan.player_names}}</small>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<h3>{% trans 'Latest Events' %}</h3>
|
||||
<ul class="fa-ul">
|
||||
{% for event in latest_event_list %}
|
||||
<li>
|
||||
<span class="fa-li fa fa-calendar-o"></span>
|
||||
<a href="{% url 'event-hanchan-list' event.pk %}">
|
||||
<time datetime="{{event.start|date:'c'}}">{{ event.start|date:'D' }} {{ event.start|date:'SHORT_DATE_FORMAT' }}</time>:
|
||||
{{event.name}}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% if season_list %}
|
||||
<h3>{% trans 'Ladder Archive' %}</h3>
|
||||
<form name="season_select">
|
||||
<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>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</form>
|
||||
{% endif %}
|
||||
@@ -5,8 +5,7 @@
|
||||
{% block teaser %}<h1>{% trans 'Dan Score for' %} {{membership.username}}</h1>{% endblock %}
|
||||
|
||||
{% block score_list %}
|
||||
<div class="grid_12">
|
||||
<h2>{% trans 'Hanchans that apply to the Dan Score' %}</h2>
|
||||
<h2 class="grid_12">{% trans 'Hanchans that apply to the Dan Score' %}</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -39,7 +38,7 @@
|
||||
</td>
|
||||
{% endfor %}
|
||||
<td class="center">{{hanchan.dan_points}}</td>
|
||||
<td>{{ hanchan.comment }}</td>
|
||||
<td>{{ hanchan.player_comment }}</td>
|
||||
<td>
|
||||
{% if perms.mahjong_ranking.delete_hanchan %}
|
||||
<a href="{% url 'delete-hanchan' hanchan.pk %}"><span class="fa fa-trash" title="{% trans 'Delete Hanchan' %}"></span></a>
|
||||
@@ -51,5 +50,4 @@
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -6,7 +6,7 @@
|
||||
{% block teaser %}<h1>{% trans 'Unconfirmed Hanchans from' %} {{membership.username}}</h1>{% endblock %}
|
||||
|
||||
{% block score_list %}
|
||||
<h2>{% trans 'Invalid hanchans with' %} {{membership.username}}</h2>
|
||||
<h2 class="grid_12">{% trans 'Invalid hanchans with' %} {{membership.username}}</h2>
|
||||
<table>
|
||||
<thead><tr>
|
||||
<th>{% trans 'Event' %}</th>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
{% block teaser %}<h1>{% trans 'Kyu Score for' %} {{membership.username}}</h1>{% endblock %}
|
||||
|
||||
{% block score_list %}
|
||||
<h2>{% trans 'Hanchans that apply to the Kyu Score' %}</h2>
|
||||
<h2 class="grid_12">{% trans 'Hanchans that apply to the Kyu Score' %}</h2>
|
||||
<table>
|
||||
<thead><tr>
|
||||
<tr>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{% block teaser %}<h1>{% trans 'Ladder Score for' %} {{membership.username}} / {{ season }}</h1>{% endblock %}
|
||||
|
||||
{% block score_list %}
|
||||
<h2>{% trans 'Hanchans that apply to the Ladder Score' %} - {{ season }}</h2>
|
||||
<h2 class="grid_12">{% trans 'Hanchans that apply to the Ladder Score' %} - {{ season }}</h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
{% extends "mahjong_ranking/page.html" %}
|
||||
{% load i18n comments%}
|
||||
{% load i18n comments humanize thumbnail %}
|
||||
|
||||
{% block title %}Mahjong Ladder - {{ season }}{% endblock %}
|
||||
|
||||
{% block teaser %}
|
||||
<h1>Mahjong Ladder - {{ season }}</h1>
|
||||
<div id="teaser_text">
|
||||
<ul class="info">
|
||||
<ul class="info">
|
||||
<li><span class="fa fa-calendar-o"></span> {% trans 'Start' %}: {{ season_start|date:'SHORT_DATE_FORMAT' }}</li>
|
||||
<li><span class="fa fa-calendar-o"></span> {% trans 'End' %}: {{ season_end|date:'SHORT_DATE_FORMAT' }}</li>
|
||||
<li><span class="fa fa-users"></span> {% trans 'Participants' %}: {{ seasonranking_list.count }}</li>
|
||||
@@ -13,6 +14,8 @@
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block redbox %}{% include 'mahjong_ranking/ladder_redbox.html' %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<table>
|
||||
<thead>
|
||||
@@ -35,11 +38,13 @@
|
||||
{% for player in seasonranking_list %}
|
||||
<tr>
|
||||
<td class="center">{{player.placement}}.</td>
|
||||
<td><a href="{{ player.get_absolute_url }}?season={{season}}"><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}}"><img
|
||||
src="{% thumbnail player.user.avatar|default:'unknown_profile.jpg' 'avatar' %}"
|
||||
width="70" height="70" class="avatar" alt=""/></a></td>
|
||||
<td><a href="{{ player.get_absolute_url }}?season={{season}}">{{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="center">{{player.avg_placement|ordinal }}</td>
|
||||
<td class="right">{{player.avg_score|floatformat:0|intcomma }}</td>
|
||||
<td class="right">{{player.hanchan_count}}</td>
|
||||
<td class="right">{{player.good_hanchans}}</td>
|
||||
<td class="right">{{player.won_hanchans}}</td>
|
||||
@@ -52,31 +57,4 @@
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endblock %}
|
||||
|
||||
{% block redbox %}
|
||||
<h2>{% trans 'Latest Hanchans' %}</h2>
|
||||
<ul class="fa-ul">
|
||||
{% for hanchan in latest_hanchan_list %}
|
||||
<li><span class="fa-li fa fa-table"></span> <a href="{% url 'event-hanchan-list' hanchan.event.pk %}">{{hanchan.event.name}}</a>
|
||||
{{hanchan.start|time:'H:i'}}:
|
||||
<small>{{hanchan.player_names}}</small>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<h3>{% trans 'Latest Events' %}</h3>
|
||||
<ul class="fa-ul">
|
||||
{% for event in latest_event_list %}
|
||||
<li><span class="fa-li fa fa-calendar-o"></span> <a href="{% url 'event-hanchan-list' event.pk %}">{{event.name}}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<h3>{% trans 'Ladder Archive' %}</h3>
|
||||
<form name="season_select">
|
||||
<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>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
@@ -9,6 +9,7 @@ from django.test import TestCase
|
||||
|
||||
|
||||
class SimpleTest(TestCase):
|
||||
|
||||
def test_basic_addition(self):
|
||||
"""
|
||||
Tests that 1 + 1 always equals 2.
|
||||
|
||||
@@ -13,19 +13,33 @@ import views
|
||||
|
||||
urlpatterns = patterns(
|
||||
'',
|
||||
# url('^$', RedirectView.as_view(pattern_name='mahjong-ladder', permanent=True)),
|
||||
url('^$',views.SeasonRankingList.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.SeasonRankingList.as_view(), name="mahjong-ladder"),
|
||||
url(r'^mahjong-ladder/(?P<season>[\d]+)/$', views.SeasonRankingList.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"),
|
||||
url(r'^$', RedirectView.as_view(
|
||||
url='/ranking/mahjong-ladder/', permanent=True)
|
||||
),
|
||||
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.SeasonRankingList.as_view(),
|
||||
name="mahjong-ladder"),
|
||||
url(r'^mahjong-ladder/(?P<season>[\d]+)/$',
|
||||
views.SeasonRankingList.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"),
|
||||
)
|
||||
|
||||
@@ -6,7 +6,7 @@ from django.core.urlresolvers import reverse
|
||||
import django.forms
|
||||
import django.http
|
||||
from django.contrib.messages.views import SuccessMessageMixin
|
||||
from django.utils.translation import gettext as _
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.views import generic
|
||||
|
||||
from events.models import Event
|
||||
@@ -21,14 +21,15 @@ kyu_dan_order = {
|
||||
'-hanchan_count': ('-hanchan_count',),
|
||||
'+rank': ('-kyu', 'dan'),
|
||||
'-rank': ('-dan', 'kyu'),
|
||||
'+score': ('dan_points', 'kyu_points'),
|
||||
'-score': ('-dan_points', '-kyu_points'),
|
||||
'+score': ('dan_points', '-dan', 'kyu_points'),
|
||||
'-score': ('-dan_points', 'dan', '-kyu_points'),
|
||||
'+username': ('user__username',),
|
||||
'-username': ('-user__username',)
|
||||
}
|
||||
|
||||
|
||||
class DeleteHanchan(EventDetailMixin, PermissionRequiredMixin, generic.DeleteView):
|
||||
class DeleteHanchan(EventDetailMixin, PermissionRequiredMixin,
|
||||
generic.DeleteView):
|
||||
"""
|
||||
Fragt zuerst nach, ob die Hanchan wirklich gelöscht werden soll.
|
||||
Wir die Frage mit "Ja" beantwortet, wird die die Hanchan gelöscht.
|
||||
@@ -43,7 +44,8 @@ class DeleteHanchan(EventDetailMixin, PermissionRequiredMixin, generic.DeleteVie
|
||||
kwargs={'event': self.object.event.pk})
|
||||
|
||||
|
||||
class HanchanForm(SuccessMessageMixin, EventDetailMixin, PermissionRequiredMixin, generic.UpdateView):
|
||||
class HanchanForm(SuccessMessageMixin, EventDetailMixin,
|
||||
PermissionRequiredMixin, generic.UpdateView):
|
||||
"""
|
||||
Ein Formular um neue Hanchans anzulegen, bzw. eine bestehende zu
|
||||
bearbeitsen
|
||||
@@ -68,7 +70,8 @@ class HanchanForm(SuccessMessageMixin, EventDetailMixin, PermissionRequiredMixin
|
||||
return forms.HanchanForm
|
||||
|
||||
def get_object(self, queryset=None):
|
||||
if self.kwargs.get('hanchan') and self.request.user.has_perm('mahjong_ranking.change_hanchan'):
|
||||
if self.kwargs.get('hanchan') and self.request.user.has_perm(
|
||||
'mahjong_ranking.change_hanchan'):
|
||||
hanchan = models.Hanchan.objects.get(id=self.kwargs['hanchan'])
|
||||
self.event = hanchan.event
|
||||
elif self.kwargs.get('event'):
|
||||
@@ -93,7 +96,9 @@ class HanchanForm(SuccessMessageMixin, EventDetailMixin, PermissionRequiredMixin
|
||||
if self.kwargs.get('hanchan'):
|
||||
return _('%s has been updated successfully.') % self.object
|
||||
else:
|
||||
return _('%s has been added successfully. You can now add a new one.') % self.object
|
||||
return _(
|
||||
'%s has been added successfully. You can now add a new '
|
||||
'one.') % self.object
|
||||
|
||||
|
||||
class EventHanchanList(EventDetailMixin, generic.ListView):
|
||||
@@ -129,7 +134,26 @@ class EventRankingList(EventDetailMixin, generic.ListView):
|
||||
raise django.http.Http404(_('Event does not exist'))
|
||||
|
||||
|
||||
class KyuDanRankingList(generic.ListView):
|
||||
class MahjongMixin(object):
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(MahjongMixin, self).get_context_data(**kwargs)
|
||||
try:
|
||||
context['season'] = self.season
|
||||
context['season_start'] = date(year=self.season, month=1, day=1)
|
||||
context['season_end'] = date(year=self.season, month=12, day=31)
|
||||
context['season_list'] = models.SeasonRanking.objects.season_list
|
||||
except AttributeError:
|
||||
pass
|
||||
context[
|
||||
'latest_hanchan_list'] = \
|
||||
models.Hanchan.objects.confirmed_hanchans()[
|
||||
:3]
|
||||
context['latest_event_list'] = Event.objects.latest_events(num=3)
|
||||
return context
|
||||
|
||||
|
||||
class KyuDanRankingList(MahjongMixin, generic.ListView):
|
||||
"""
|
||||
Anzeige aller Spiele mit ihrem Kyu bzw Dan Grad.
|
||||
"""
|
||||
@@ -145,30 +169,22 @@ class KyuDanRankingList(generic.ListView):
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = models.KyuDanRanking.objects.all().order_by(*self.order_by)
|
||||
return queryset.select_related('user__membership')
|
||||
return queryset.select_related()
|
||||
|
||||
|
||||
class SeasonRankingList(generic.ListView):
|
||||
class SeasonRankingList(MahjongMixin, generic.ListView):
|
||||
model = models.SeasonRanking
|
||||
paginate_by = 25
|
||||
season = None
|
||||
|
||||
def get_queryset(self):
|
||||
self.season = int(self.kwargs.get('season', date.today().year))
|
||||
queryset = self.model.objects.filter(season=self.season,
|
||||
placement__isnull=False)
|
||||
queryset = self.model.objects.filter(
|
||||
season=self.season,
|
||||
placement__isnull=False
|
||||
)
|
||||
return queryset.select_related()
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(SeasonRankingList, self).get_context_data(**kwargs)
|
||||
context['season'] = self.season
|
||||
context['season_start'] = date(year=self.season, month=1, day=1)
|
||||
context['season_end'] = date(year=self.season, month=12, day=31)
|
||||
context['season_list'] = models.SeasonRanking.objects.season_list
|
||||
context['latest_hanchan_list'] = models.Hanchan.objects.confirmed_hanchans()[:3]
|
||||
context['latest_event_list'] = Event.objects.archive()[:3]
|
||||
return context
|
||||
|
||||
|
||||
class PlayerScore(LoginRequiredMixin, generic.ListView):
|
||||
paginate_by = 25
|
||||
@@ -176,9 +192,12 @@ class PlayerScore(LoginRequiredMixin, generic.ListView):
|
||||
def get(self, request, *args, **kwargs):
|
||||
user_model = auth.get_user_model()
|
||||
try:
|
||||
self.user = user_model.objects.get(username=self.kwargs.get('username'))
|
||||
self.user = user_model.objects.get(
|
||||
username=self.kwargs.get('username'))
|
||||
except user_model.DoesNotExist:
|
||||
raise django.http.Http404(_("No user found matching the name {}").format(self.kwargs.get('username')))
|
||||
raise django.http.Http404(
|
||||
_("No user found matching the name {}").format(
|
||||
self.kwargs.get('username')))
|
||||
return super(PlayerScore, self).get(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
@@ -235,6 +254,7 @@ class PlayerLadderScore(PlayerScore):
|
||||
self.season = int(self.request.GET.get('season'))
|
||||
except:
|
||||
self.season = date.today().year
|
||||
hanchan_list = models.Hanchan.objects.season_hanchans(user=self.user, season=self.season)
|
||||
hanchan_list = models.Hanchan.objects.season_hanchans(
|
||||
user=self.user, season=self.season)
|
||||
print hanchan_list
|
||||
return hanchan_list
|
||||
|
||||
Reference in New Issue
Block a user